mongodb - 运行查询之前未创建 Mongoose 索引

标签 mongodb mongoose

当运行我的测试时,我收到一条错误,指出我在标题字段上没有设置文本索引,但当运行我的应用程序时,文本搜索可以在同一模型上正常工作,并且不会抛出错误。

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/

相关文章:

mysql - MongoDB 复杂的按功能选择计数组

node.js - 关闭 Mongoose 连接 Lambda

mongodb - 使用 MongoDB 时存储大量文档的生产最佳实践是什么?

javascript - 根据日期(月份)使用 node.js 和 mongodb 过滤和重新排列结果

node.js - Mongoose 或查询

node.js - 了解node Angular Express和mongo之间的通信

mongodb - 获取给定用户每个对话的未读消息计数

node.js - 如何将此mongodb对象转换为普通版本?

javascript - mongoose.Promise 和 promisifyAll 有什么区别?

ruby-on-rails - Ruby on Rails 动态模型