是否可以在Meteor 1.7+中预订文本搜索光标

时间:2018-09-26 23:00:23

标签: mongodb meteor

以前,我曾经写

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

在尝试查找更多信息时,this answer提到fields参数需要包含在投影中,例如

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

但是,流星没有没有.project方法。

有什么解决方案?

1 个答案:

答案 0 :(得分:1)

下面有一个已创建的mini-repro指南。它显示了如何像最初报告的那样执行(索引)文本搜索以引发错误。

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

因此,这是一份简短的清单,列出了可能出了什么问题:

  • 1.7和更高版本正在使用新的Mongo版本和node-Mongo驱动程序版本-此更新是否也更新了这些版本?如果在生产中-您是否已更新到数据库服务器上的相应Mongo版本?
  • 从Mongo 3.2开始,新的version 3 of text indexing正在使用中。也许您以前的Meteor版本在执行db.createIndex时使用了较早的Mongo以及以前的文本索引。我还没有发现任何破坏向后兼容性的信息,但这可能是原因。如果您是开发人员,则可以执行db.collection.getIndexes()轻松地进行验证。例如,下面创建的repro项目具有以下输出:

获取当前索引:

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”分数的工作文本搜索:

为了验证它是否正在与新项目一起工作(发布METEOR@1.7.0.5),您可以复制以下步骤:

  1. 创建一个新项目并安装faker(以快速创建一些文本):
$ meteor create metasearch
$ cd metasearch
$ meteor npm install --save faker
$ meteor
  1. Texts中创建一个名为/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 { … }