当运行我的测试时,我收到一条错误,指出我在标题字段上没有设置文本索引,但当运行我的应用程序时,文本搜索可以在同一模型上正常工作,并且不会抛出错误。
text index required for $text query (no such collection 'test-db.torrents')
import mongoose from 'mongoose';
import Category from './category';
const Schema = mongoose.Schema;
const Torrent = new Schema({
title: {
type: String
},
category: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Category',
required: true,
index: true
},
size: Number,
details: [
{
type: String
}
],
swarm: {
seeders: Number,
leechers: Number
},
lastmod: {
type: Date,
default: Date.now()
},
imported: {
type: Date,
default: Date.now()
},
infoHash: {
type: String,
unique: true,
index: true
}
});
Torrent.index({
title: 'text'
}, {
background: false
});
export default mongoose.model('Torrent', Torrent);
我正在使用ava用于测试,这是我的测试用例。
import mongoose from 'mongoose';
import request from 'supertest';
import test from 'ava';
import {makeApp} from '../helpers';
test.before(() => {
mongoose.Promise = Promise;
mongoose.connect('mongodb://localhost:27017/astro-test-db');
});
test.after.always(() => {
mongoose.connection.db.dropDatabase(() => {
mongoose.disconnect();
});
});
// Should return [] since HL3 doesn't exist.
test('should return no search results', async t => {
const app = makeApp();
const res = await request(app).get(`/api/search?q=HL3`);
t.is(res.status, 200);
t.is(res.body.error, {});
t.is(res.body.torrents.length, 0);
});
这是 ava 的完整输出,您可以看到标题的索引不是使用“text”或 background: false
创建的。
➜ astro git:(develop) ✗ yarn ava test/routes/search.js -- --verbose
yarn ava v0.24.6
$ "/Users/xo/code/astro/node_modules/.bin/ava" test/routes/search.js --verbose
Mongoose: categories.ensureIndex({ title: 1 }, { unique: true, background: true })
Mongoose: torrents.ensureIndex({ category: 1 }, { background: true })
Mongoose: torrents.count({}, {})
Mongoose: categories.ensureIndex({ slug: 1 }, { unique: true, background: true })
Mongoose: torrents.find({ '$text': { '$search': 'x' } }, { limit: 100, sort: { score: { '$meta': 'textScore' }, 'swarm.seeders': -1 }, fields: { score: { '$meta': 'textScore' } } })
✖ should return no search results
1 test failed [13:59:07]
should return no search results
/Users/xo/code/astro/test/routes/search.js:24
23: t.is(res.status, 200);
24: t.is(res.body.error, {});
25: t.is(res.body.torrents.length, 0);
Difference:
- Object {
- code: 27,
- codeName: "IndexNotFound",
- errmsg: "text index required for $text query (no such collection \'astro-test-db.torrents\')",
- message: "text index required for $text query (no such collection \'astro-test-db.torrents\')",
- name: "MongoError",
- ok: 0,
- }
+ Object {}
_callee$ (test/routes/search.js:24:7)
tryCatch (node_modules/regenerator-runtime/runtime.js:65:40)
Generator.invoke [as _invoke] (node_modules/regenerator-runtime/runtime.js:303:22)
Generator.prototype.(anonymous function) [as next] (node_modules/regenerator-runtime/runtime.js:117:21)
step (test/routes/search.js:19:191)
error Command failed with exit code 1.
最佳答案
您应该确保索引是在“前台”创建的,因为“后台”创建是默认的。
Torrent.index({
title: 'text'
},{ "background": false });
至少对于您的测试而言,否则查询有可能在创建索引之前运行。设置 { background: false }
可确保索引在其他操作运行之前就存在。这与default behavior相反。 MongoDB 的,因此需要显式设置。
在生产环境中,通常最好通过其他方式部署索引。此外,“前台”创建会导致较小的索引大小,但当然会“阻塞”IO,但通常在生产中至少执行一次仍然会更好。
引用自 documentation
By default, MongoDB builds indexes in the foreground, which prevents all read and write operations to the database while the index builds. Also, no operation that requires a read or write lock on all databases (e.g. listDatabases) can occur during a foreground index build.
这意味着发生这种情况时不能进行读取或写入。因此,在“前台”创建模式下创建索引时无法插入数据,也无法运行查询。
至于大小,在引文的同一页下方一点:
Background index builds take longer to complete and result in an index that is initially larger, or less compact, than an index built in the foreground. Over time, the compactness of indexes built in the background will approach foreground-built indexes.
因此,您可以在后台创建索引,“随着时间的推移”,这些索引将在生产环境中缩减为更紧凑的大小。但出于测试和开发目的,您的默认设置实际上应该始终是在“前台”创建,以免遇到计时问题。
作为最小测试用例:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.set('debug', true);
var testSchema = new Schema({
title: { type: String }
});
testSchema.index({
title: 'text'
},{ background: false });
var Test = mongoose.model('Test', testSchema);
mongoose.connect('mongodb://localhost/texttest');
Test.create({ title: 'something here' },function(err,doc) {
Test.find({ "$text": { "$search": "something" } },function(err,doc) {
if (err) throw err;
console.log(doc);
Test.collection.drop(function(err) {
if (err) throw err;
mongoose.disconnect();
});
});
});
作为替代方法,自动关闭 Mongoose 自动索引功能并手动设置,然后通过 .ensureIndexes()
手动调用创建:
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.set('debug', true);
var testSchema = new Schema({
title: { type: String }
},{ autoIndex: false });
testSchema.index({
title: 'text'
},{ background: false });
var Test = mongoose.model('Test', testSchema);
mongoose.connect('mongodb://localhost/texttest');
// Manually set indexing to on
Test.schema.options.autoIndex = true;
//console.log(Test.schema.options);
Test.ensureIndexes(function(err) {
if (err) throw err;
Test.create({ title: 'something here' },function(err,doc) {
Test.find({ "$text": { "$search": "something" } },function(err,doc) {
if (err) throw err;
console.log(doc);
Test.collection.drop(function(err) {
if (err) throw err;
mongoose.disconnect();
});
});
});
});
关于mongodb - 运行查询之前未创建 Mongoose 索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44469310/