使用Mongoose更新MongoDB记录中的数组

3
什么是在mongodb记录中更新数组值的最佳方法?目前,我的尝试方式如下:
Record.find({ 'owner': owner}, {}, {sort: { date: -1 }}, function(err, record){
    if(!err){
        for (var i = 0; i < record[0].array.length; i++){
            record[0].array[i].score = 0;

            record[0].array[i].changed = true;

            record[0].save();
        }
    }
 });

下面是该架构图:

var recordSchema = mongoose.Schema({
    owner: {type: String},
    date: {type: Date, default: Date.now},
    array: mongoose.Schema.Types.Mixed
});

目前,我可以看到数组被更新了,在保存时也没有报错,但是当我再次查询数据库时,数组并没有被更新。


为什么要在循环内保存文档? - max
我已经尝试了内部和外部,但数组仍未更新。 - alreadytaken
我认为你的查询语句也应该在参数中使用null而不是一个空对象。Mongoose文档 - max
2个回答

14

如果您将属性命名为 "array",并不会对其目的有任何解释作用。从代码中可以看出,您希望将其中每个项的得分设置为零。请注意,您的保存操作当前被忽略,因为只能保存顶级Mongoose文档,而无法保存嵌套文档。

使用数组更新运算符,例如$push$addToSet等,可以通过单个数据库命令完成某些数组查找和修改操作。但是我没有看到任何运算符可以直接在单个操作中进行所需的更改。因此,我认为您需要查找记录、修改数组数据并保存它。(请注意,findOne是一个便捷函数,如果您只关心第一个匹配项,则可以使用它,这似乎是您的情况)。

Record.findOne({ 'owner': owner}, {}, {sort: { date: -1 }}, function(err, record){
    if (err) {
       //don't just ignore this, log or bubble forward via callbacks
       return;
    }
    if (!record) {
        //Record not found, log or send 404 or whatever
        return;
    }
    record.array.forEach(function (item) {
        item.score = 0;
        item.changed = true;
    });
    //Now, mongoose can't automatically detect that you've changed the contents of 
    //record.array, so tell it
    //see http://mongoosejs.com/docs/api.html#document_Document-markModified
    record.markModified('array');
    record.save();        
 });

成功了!我之所以只是将属性命名为“array”,是为了简化问题。我还将其更改为findOne,感谢您的建议。将数组从mongoose.Schema.Types.Mixed类型更改为子文档http://mongoosejs.com/docs/subdocs.html是否会使更新信息更容易? - alreadytaken
我认为没有任何模式可以使这成为一个一次操作。你可以将“数组”文档存储在完全分离的集合中,具有score,record_id,changed,order属性,在这种情况下,您可以使用多重更新一次性重置它们所有。但是,您会失去在数组中管理顺序的好能力。因此,这取决于数组中的顺序对您的应用程序是否重要,以及这种批量重置是常见情况还是边缘情况,而不是需要为读取操作加载所有数据。 - Peter Lyons

3
如果你有一个文档的 mongoose 对象,你当然可以像问题中那样更新数组,但需要注意以下“警告”。事实上这是mongoose的陷阱。Mongoose无法跟踪混合类型数组的更改,必须使用markModified函数:
doc.mixed.type = 'changed';
doc.markModified('mixed.type');
doc.save() // changes to mixed.type are now persisted

是的,这是一个很大的问题!非常感谢你! - knutole

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接