如何在MongoDB中创建持久的唯一索引

时间:2014-10-27 03:03:43

标签: node.js mongodb mongoose

免责声明:我使用猫鼬的时间不到48小时。

我的模型看起来像这样:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

//Schema definition
var CategorySchema = new Schema({
    name: String,
    url: { type: [String], index: true },
    extra: Array,
    frequency: Number,
    last_processed: Date
});

// Model definition
var Category = mongoose.model('categories', CategorySchema);

当我的应用程序启动时,它有一个方法来自动更新集合,使用如下结构的js文件(不受我控制的js文件):

var categories = {
    retailer: 'ret1',
    name: 'c1',
    url: 'url1',
    extra: ['tag1'],
    frequency: 2,
    last_processed: ''
}, {
    retailer: 'ret2',
    name: 'c2',
    url: 'url2',
    extra: ['tag2'],
    frequency: 2,
    last_processed: ''
}, 
  ........
];

module.exports = categories;

我使用循环创建记录:

var Category = mongoose.model('categories');
for (var j = 0; j < categories.length; j++) {
    new Category(categories[j]).save();
}

我的问题如下:

当我第一次启动我的应用程序时,db.categories.count()= 308(应该是这样)。但是,如果我关闭应用程序并重新启动,则count()= 616,因此它会复制记录。我认为使用索引会避免这种行为,但显然不会。关于索引的文档对我来说并不清楚,来自RDB背景。我在调试中看到索引已创建:Mongoose: categories.ensureIndex({ url: 1 }) { safe: undefined, background: true }

如何在我的收藏中创建一个持久的唯一索引,所以我从来没有重复?在这个简单的启动例程之后,我将不断地在这个表上写,我是否必须在每次写入后重新创建一个索引?

经过更多研究后更新:

我写的308网址中没有重复项,我从空数据库开始。

1 个答案:

答案 0 :(得分:1)

您可以将索引定义为唯一:

var CategorySchema = new Schema({
    name: String,
    url: { 
        type: String, 
        index: {
            unique: true
        }
    },
    extra: Array,
    frequency: Number,
    last_processed: Date
});

然后,给你添加回调save()

for (var j = 0; j < categories.length; j++) {
    new Category(categories[j]).save(function(err, doc) {
        console.error(err);
    });
}

您会看到以下打印

{ [MongoError: insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.categories.$url_1  dup key: { : "url2" }]
  name: 'MongoError',
  code: 11000,
  err: 'insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.categories.$url_1  dup key: { : "url2" }' }

您可以使用findOneAndUpdate,在给定选项upsert: true的情况下,可以创建或更新对象。如果您不想更新但只是跳过,因为使用save()存在类别可能已经足够了。

for (var j = 0; j < categories.length; j++) {
    Category.findOneAndUpdate(
        { url: categories[j].url },
        categories[j],
        { upsert: true },
        function(err, doc) {
            console.error(err);
        }
    );
}