首页 > 解决方案 > 是否可以在 Meteor 1.7+ 中订阅文本搜索光标

问题描述

以前,我曾经写过

MyCollection.find({ $text: { $search: 'foo' } }, {
  fields: {
    score: { $meta: "textScore" }
  },
  sort: {
    score: { $meta: "textScore" }
  }
});

但是,现在我得到一个错误

I20180926-18:26:08.708(-4)? Exception from sub mysubscription id ZeSWJcoghED3t6Eq6 Error: Exception while polling query {"collectionName":"my-collection","selector":{"$text":{"$search":"foo"}},"options":{"transform":null,"limit":25,"sort":{"score":{"$meta":"textScore"}}}}: must have $meta projection for all $meta sort keys
I20180926-18:26:08.709(-4)?     at PollingObserveDriver._pollMongo (packages/mongo/polling_observe_driver.js:165:11)
I20180926-18:26:08.709(-4)?     at Object.task (packages/mongo/polling_observe_driver.js:93:12)
I20180926-18:26:08.710(-4)?     at Meteor._SynchronousQueue.SQp._run (packages/meteor.js:987:16)
I20180926-18:26:08.710(-4)?     at packages/meteor.js:964:12

当我尝试查找更多信息时,此答案提到该fields参数需要包含在投影中,例如

collection.find({
    $text:
      {
        $search: filter,
        $caseSensitive: false,
        $diacriticSensitive: true
      }
    })
    .project({ score: { $meta: "textScore" } })
    .sort({score:{$meta:"textScore"}})

但是,Meteor没有方法.project

解决方案是什么?

标签: mongodbmeteor

解决方案


下面有一个创建的迷你复制指南。它显示了如何执行(索引)文本搜索作为您最初报告的引发错误的搜索。

因此,可以假设错误的来源,例如迁移到 Meteor 1.7+ / Mongo 3.6+ 或代码中。迁移很有可能包括原因,因为最近在论坛和 SO 上有很多关于升级到 1.7 问题的帖子。

因此,这里有一个简短的清单,说明可能出了什么问题:

  • 新的 Mongo 版本和 node-Mongo 驱动程序版本正在用于 1.7+ - 更新是否也正确更新了这些?如果在生产中-您是否在数据库服务器上更新到相应的 Mongo 版本?
  • 从 Mongo 3.2 开始,有一个新的第 3 版文本索引正在使用中。也许您以前的 Meteor 版本在执行时使用了带有以前文本索引的旧 Mongo db.createIndex。我没有发现任何信息表明它破坏了向后兼容性,但这可能是一个可能的原因。如果您在 dev 上,您可以通过执行轻松验证db.collection.getIndexes(). 例如,以下创建的复制项目具有以下输出:

获取当前索引:

meteor:PRIMARY> db.texts.getIndexes()
[
    {
        "v" : 2,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "meteor.texts"
    },
    {
        "v" : 2,
        "key" : {
            "_fts" : "text",
            "_ftsx" : 1
        },
        "name" : "text_text",
        "ns" : "meteor.texts",
        "weights" : {
            "text" : 1
        },
        "default_language" : "english",
        "language_override" : "language",
        "textIndexVersion" : 3
    }
]

复制工作文本搜索,包括 $meta "textScore" 分数:

为了验证它是否正在使用新项目(Release METEOR@1.7.0.5),您可以重现以下步骤:

  1. 创建一个新项目并安装 faker(快速创建一些文本):
$ meteor create metasearch
$ cd metasearch
$ meteor npm install --save faker
$ meteor
  1. 创建一个名为Textsin的集合/imports/Texts.js
import { Mongo } from "meteor/mongo"
export const Texts = new Mongo.Collection('texts')
  1. 将以下服务器代码传递到/server/main.js
import { Meteor } from 'meteor/meteor'
import { Texts } from '../imports/Texts'

Meteor.startup(() => {
  import { lorem } from 'faker'
  for (let i = 0; i < 5; i++) {
    Texts.insert({
      title: lorem.words(),
      text: lorem.text()
    })
  }
})

Meteor.publish('search', function searchpub (filter) {
  const cursor = Texts.find({
    $text: {
      $search: filter,
      $caseSensitive: false,
      $diacriticSensitive: false,
    }
  }, {
    fields: {
      score: {$meta: 'textScore'},
    },
    sort: {
      score: {$meta: 'textScore'},
    },
  })

  // fallback if cursor is undefined
  if (cursor && cursor.count && cursor.count() >= 0) {
    return cursor
  } else {
    this.ready()
  }
})

正如您所看到的,它使用默认的“查询、投影和排序在一个文档中”结构,正如您最初发布的那样。

  1. 通过以下方式扩展/client/main.js代码:
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';

import './main.html';

import {Texts} from '../imports/Texts'

Template.hello.onCreated(function helloOnCreated() {
  // counter starts at 0
  this.counter = new ReactiveVar(0);

  const instance = this
  instance.autorun(() => {
    const cursor = instance.subscribe('search', 'dolor') // use a word, that often occurs
    if (cursor.ready()) {
      console.log(Texts.find().fetch())
    }
  })
});

// ... rest of the file
  1. 打开一个新的终端选项卡并打开 mongo shell 并创建一个新的文本索引:
$ meteor mongo
$ db.texts.createIndex({text:"text"})

输出应类似于:

{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1,
    "operationTime" : Timestamp(1538031016, 1),
    "$clusterTime" : {
        "clusterTime" : Timestamp(1538031016, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    }
}
  1. 清理,取消正在运行的流星并重新启动。

与此同时,Meteor.startup诱导插入应该已经创建了大量要搜索的文档,但它们可能还没有被添加到索引中。

您可以取消正在运行的实例并再次重新启动几次(或增加启动时要插入的文档数量)以获得大量匹配。

  1. 运行客户端并查看潜艇

localhost:3000默认情况下运行时,您应该得到类似的输出,如下所示:

Array (51) […]
​
0: {…}
_id: "n2WhMskCXBm7ziZea"
score: 1.0416666666666667
text: "Dolor at sed et dolorem tenetur a dolore voluptate incidunt. Rerum corrupti officia aut tenetur nisi officiis voluptas soluta. Fugiat eos sed expedita inventore. Esse cupiditate qui. Facere dolor quisquam ipsa a facere praesentium. Aut sunt mollitia dolore tenetur."
title: "quia est fuga"
<prototype>: Object { … }
​
1: {…}
_id: "QjAcZQLTH8Mc3jDzS"
score: 1.0110294117647058
text: "Sequi dolores omnis sequi consequatur laborum et asperiores. Accusantium repellat magnam est aut suscipit enim iure. Qui qui aut cupiditate necessitatibus commodi qui quia. Ut tempore autem provident maiores cumque necessitatibus dolores accusantium. Nostrum ut ut sunt adipisci qui consequuntur explicabo voluptas. Minima praesentium sunt facere doloribus non at dolor dolore est."
title: "est explicabo omnis"
<prototype>: Object { … }

推荐阅读