我正在尝试使用documentation和示例,将服务器端选择器添加到我的Meteor应用程序中的搜索功能中,该功能是使用Easy Search插件实现的。最终目标是通过搜索确保仅返回用户有权查看的文档。
我可以在Leaderboard示例中看到一个选择器,但是在我的代码中无法使它起作用。
版本:
Meteor 1.7.0.1
easy:[email protected]
easysearch:[email protected]
easysearch:[email protected]
[我修改了流星[C0]以演示该问题,然后'todos' example app。
注意!为了演示该问题,您需要在演示应用程序中创建一个帐户,然后创建一个列表并将其设为私有。这会将“ userId”字段添加到列表中。
然后,您可以在主要部分顶部附近的搜索框中输入搜索列表的名称;搜索结果将写入浏览器控制台。
第一个问题是,如果我从my demo code is in a repo复制代码,则会看到服务器错误'未定义searchObject:
从文档中复制,导致错误:imports / api / lists / lists.js
example in the documentation
似乎文档中有错误。
而是从页首横幅示例中工作,下面的代码可以运行,但会间歇性地返回任何结果。例如,如果我有一个名为“我的列表”的列表,并且键入搜索词“ s”,则有时该列表是从搜索中返回的,而有时不是。如果我使用MiniMongo引擎,那么一切都将正常运行。
export const MyIndex = new Index({
'collection': Lists,
'fields': ['name'],
engine: new MongoDBEngine({
selector(searchDefinition, options, aggregation) {
// retrieve the default selector
const selector = this.defaultConfiguration()
.selector(searchObject, options, aggregation)
// options.search.userId contains the userId of the logged in user
selector.userId = options.search.userId
return selector
},
}),
});
客户端和服务器:imports / api / lists / lists.js
index selector {"$or":[{"name":{"$regex":".*my.*","$options":"i"}}],"userId":"Wtrr5FRHhkKuAcrLZ"}
客户端:imports / ui / components / lists-show.js
export const MyIndex = new Index({
'collection': Lists,
'fields': ['name'],
'engine': new MongoDBEngine({
selector: function (searchObject, options, aggregation) {
let selector = this.defaultConfiguration().selector(searchObject, options, aggregation);
selector.userId = options.search.userId;
console.log('index selector', JSON.stringify(selector));
return selector;
}
}),
permission: () => {
return true;
},
});
客户端:imports / ui / components / lists-show.html
Template.Lists_show.events({
'keyup #search'(event) {
console.log('search for ', event.target.value);
const cursor = MyIndex.search(event.target.value);
console.log('count',cursor.count());
console.log('results', cursor.fetch());
},
});
编辑:我认为问题在于,虽然Minimongo引擎在客户端上运行,但MongoDBEngine在服务器上运行,并且结果存在计时问题。该文档显示使用Tracker.autorun,但这与我的React / Redux应用程序不自然匹配。如果我设法找出答案,我会发布答案-我不可能是唯一尝试执行此类操作的人。
我在React / Redux / Meteor应用程序中正常运行。注意事项:
光标MyIndex.search(searchTerm)是一个反应性数据源-您不能仅将其用作返回值。使用MiniMongo在客户端上搜索时,这不是问题,但是当您使用MongoDBEngine在服务器上搜索时,这很重要,因为它是异步的。在React中,您可以将光标包裹在withTracker中,以将数据以响应方式传递到组件。在Blaze中,您将使用autorun.tracker。这在文档中已显示,但未进行说明,花了我一段时间才了解正在发生的事情。
文档在选择器示例中有一个错误,可以很容易地纠正,但是如果您的代码中还有其他问题,则会令人困惑。
对于MongoDBEngine,必须指定'permission'-缺省不为'true'。没有它,您将看不到任何结果。
将默认选择器对象写到控制台,让我看一下它是如何构造的,然后创建一个新的选择器,该选择器返回公开的或由用户创建的MyDocs。
我的代码在下面。万一它对其他人有帮助,我已经展示了如何搜索标签,这些标签是具有名称属性的对象,该对象存储在标签集合中。每个MyDoc都有一个“标签”属性,该属性是标签ID的数组。选择器首先搜索“标记”集合以查找名称与搜索词匹配的标记,然后在MyDocs中选择文档,并在其doc.tags数组中选择这些标记的ID。
也许有更好的方法来查找搜索词或构建标签搜索,但这是我可以使用的方法。
在服务器和客户端上:
<input id="search" type="text" placeholder="search..." />
仅客户端代码中的反应组件:
import { Index, MongoDBEngine } from 'meteor/easy:search';
export const MyDocs = new Mongo.Collection('mydocs');
export const Tags = new Mongo.Collection('tags');
export const MyIndex = new Index({
'collection': MyDocs,
'fields': ['name'],
'engine': new MongoDBEngine({
'selector': function (searchObject, options, aggregation) {
const selector = this.defaultConfiguration().selector(searchObject, options, aggregation);
console.log('default selector', selector); // this searches on name only
// find docs by tag as well as by name
const searchTerm = searchObject.name;
const matchingTags = Tags.find({ 'name': { '$regex': searchTerm } }).fetch();
const matchingTagIds = matchingTags.map((tag) => tag._id);
selector.$or.push({ 'tags': { '$in': matchingTagIds } });
const newSelector = {
'$and': [
{
'$or': [
{ 'isPublic': { '$eq': true } },
{ 'createdBy': options.search.userId },
],
},
{
'$or': selector.$or,
},
],
};
return newSelector;
},
'fields': (searchObject, options) => ({
'_id': 1,
'createdBy': 1,
'name': 1,
}),
'sort': () => ({ 'name': 1 }),
}),
'permission': () => true,
});