在运行查询之前未创建猫鼬索引 [英] Mongoose Index not being Created before Query is Run

查看:114
本文介绍了在运行查询之前未创建猫鼬索引的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

运行测试时出现错误,提示我没有在标题字段上设置文本索引,但是在运行应用程序时,文本搜索在相同模型下也可以正常工作,并且不会引发错误.

When running my tests I'm getting an error stating I don't have a text index setup on the title field yet when running my application text searches work fine with this same model and don't throw the error.

$ text查询所需的文本索引(没有这样的集合"test-db.torrents")

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 进行测试,这是我的测试用例.

I'm using ava for testing and here is my test case.

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创建的.

Here's the full ouput from ava, as you can see the index for title doesn't get created with 'text' or 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.

推荐答案

由于默认创建背景",因此应确保在前景"中创建索引.

You should make sure the index is created in the "foreground" since "background" creation is default.

Torrent.index({
    title: 'text'
},{ "background": false });

至少对于您的测试而言,否则可能会在创建索引之前运行查询.设置{ background: false }可以确保在运行其他操作之前索引已存在.这与 MongoDB的默认行为,因此它必须是一个明确的设置.

At least for your tests, otherwise there is a possibility that the query can run before the index is created. Setting { background: false } makes sure the index is there before other operations can run. This is opposite to the default behavior of MongoDB, so it needs to be an explicit setting.

在生产环境中,通常最好还是通过其他方式部署索引.同样,前台"创建会导致较小的索引大小,但当然会阻塞" IO,但是通常在生产中至少执行一次更好.

In production environments it is usually best to deploy indexes by other means anyway. Also "foreground" creation results in a smaller index size but of course "blocks" IO, but it's still generally better to do this at least once in production.

文档 <中的引用

Citation from documentation

默认情况下,MongoDB在前台构建索引,这样可以防止在索引构建过程中对数据库进行所有读写操作.此外,在前台索引构建期间,不会发生需要对所有数据库(例如listDatabases)进行读或写锁定的操作.

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.

这意味着发生这种情况时,不会发生任何读取或写入操作.因此,在前台"创建模式下创建索引时,无法插入数据,也无法运行查询.

Which means no reads or writes can occur when this happens. So data cannot be inserted and queries cannot be run whilst indexes are being created when in "foreground" creation mode.

关于大小,请从引用的同一页往下一点:

As for size, a little further down the same page from the citation:

背景索引的构建需要花费更长的时间才能完成,并且所产生的索引最初比在前景中构建的索引更大或更紧凑.随着时间的流逝,后台建立的索引的紧凑性将接近前景建立的索引.

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.

因此,您可以在后台创建索引,这些索引会在生产环境中将随着时间的推移" 缩小为更紧凑的大小.但是出于测试和开发目的,您的默认设置实际上应该始终是在前景"中创建,以便不被计时问题困扰.

So you can create indexes in the background that will "over time" come down to a more compact size in a production environment. But for testing and development purposes, your default should really always be to create in "foreground" in order not to be caught out with timing issues.

作为最小的测试用例:

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();
   });
  });
});

作为一种替代方法,自动关闭猫鼬自动索引功能并手动设置,然后通过

As an alternate approach, turn off mongooses autoindex feature automatically and set manually, then call creation manually via .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();
      });
    });
  });
});

这篇关于在运行查询之前未创建猫鼬索引的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆