There is a created mini-repro guide below. It shows how to execute a (indexed-)text search as the one you have initially reported to throw an error.
Therefore one can assume the sources of error for example in the migration to Meteor 1.7+ / Mongo 3.6+ or in the code. The migration has high chances of including the cause, as there were recently many posts on issues with upgrading to 1.7 in the forums as well as on SO.
So here is a short checklist on what could have gone wrong:
- A new Mongo version and node-Mongo driver version is in use for 1.7+ - did the update also update these correct? If on production - did you update to the respective Mongo Version on your db Server?
- Since Mongo 3.2 there is a new version 3 of text indexing in use. Maybe your previous Meteor version used an older Mongo with former text indexing when executing
db.createIndex
. I have not found any info that it breaks backwards compatibility but it could be a possible cause. If you are on dev you can easily verify by executing db.collection.getIndexes()
. The below created repro project for example has the following output:
Get current indexes:
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
}
]
- If the cause is due to an index version mismatch, you can drop the index and re-create it so that the versions match.
- If there is still a problem and you can't figure it out, you can still rely on the
Mongo.Collection.rawCollection
, that allows native operations on collections. Note this SO answer on extended requirements to integrate native Mongo operations into your Meteor environment
Reproduction of working text search including $meta "textScore" scores:
In order to verify, that it is working with a new project (Release METEOR@1.7.0.5
) you can reproduce the following steps:
- Create a new project and install faker (to create some texts fast):
$ meteor create metasearch
$ cd metasearch
$ meteor npm install --save faker
$ meteor
- Create a collection named
Texts
in /imports/Texts.js
:
import { Mongo } from "meteor/mongo"
export const Texts = new Mongo.Collection('texts')
- Past the following server code to
/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()
}
})
As you can see it uses the default "query, projection and sort in one document" structure, as you initially posted.
- Extend the
/client/main.js
code by the following:
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
- Open a new terminal tab and open the mongo shell and create a new text index:
$ meteor mongo
$ db.texts.createIndex({text:"text"})
Output should be similar to:
{
"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)
}
}
}
- Clean, cancel the running meteor and restart.
In the meantime the Meteor.startup
induced inserts should have create a neat amount of documents to search but they may not be added to the index, yet.
You can cancel the running instance and restart again a few times (or increase the number of documents to be inserted on startup) to get a good amount of matches.
- Running the client and look at the subs
When running on localhost:3000
per default you should get a similar output like the following:
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 { … }