如何轻松实现选择器:使用React代替Blaze搜索Meteor

问题描述 投票:1回答:1

我正在尝试使用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应用程序不自然匹配。如果我设法找出答案,我会发布答案-我不可能是唯一尝试执行此类操作的人。

search meteor permissions
1个回答
0
投票

我在React / Redux / Meteor应用程序中正常运行。注意事项:

  1. 光标MyIndex.search(searchTerm)是一个反应性数据源-您不能仅将其用作返回值。使用MiniMongo在客户端上搜索时,这不是问题,但是当您使用MongoDBEngine在服务器上搜索时,这很重要,因为它是异步的。在React中,您可以将光标包裹在withTracker中,以将数据以响应方式传递到组件。在Blaze中,您将使用autorun.tracker。这在文档中已显示,但未进行说明,花了我一段时间才了解正在发生的事情。

  2. 文档在选择器示例中有一个错误,可以很容易地纠正,但是如果您的代码中还有其他问题,则会令人困惑。

  3. 对于MongoDBEngine,必须指定'permission'-缺省不为'true'。没有它,您将看不到任何结果。

  4. 将默认选择器对象写到控制台,让我看一下它是如何构造的,然后创建一个新的选择器,该选择器返回公开的或由用户创建的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,
});
© www.soinside.com 2019 - 2024. All rights reserved.