Mongoose 查找/更新子文档 [英] Mongoose find/update subdocument

查看:80
本文介绍了Mongoose 查找/更新子文档的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有文档文件夹的以下架构:

var permissionSchema = new Schema({
    role: { type: String },
    create_folders: { type: Boolean },
    create_contents: { type: Boolean }
});

var folderSchema = new Schema({
    name: { type: string },
    permissions: [ permissionSchema ]
});

因此,对于每个页面,我可以拥有许多权限.在我的 CMS 中有一个面板,我在其中列出了所有文件夹及其权限.管理员可以编辑单个权限并保存.

So, for each Page I can have many permissions. In my CMS there's a panel where I list all the folders and their permissions. The admin can edit a single permission and save it.

我可以轻松地保存整个 Folder 文档及其权限数组,其中只修改了一个权限.但我不想保存所有文档(真正的架构有更多的字段)所以我这样做了:

I could easily save the whole Folder document with its permissions array, where only one permission was modified. But I don't want to save all the document (the real schema has much more fields) so I did this:

savePermission: function (folderId, permission, callback) {
    Folder.findOne({ _id: folderId }, function (err, data) {
        var perm = _.findWhere(data.permissions, { _id: permission._id });                

        _.extend(perm, permission);

        data.markModified("permissions");
        data.save(callback);
    });
}

但问题是perm 总是未定义!我试图以这种方式静态"获取权限:

but the problem is that perm is always undefined! I tried to "statically" fetch the permission in this way:

var perm = data.permissions[0];

而且效果很好,所以问题是 Underscore 库无法查询权限数组.所以我想有一种更好的(和有效的)方法来获取所获取文档的子文档.

and it works great, so the problem is that Underscore library is not able to query the permissions array. So I guess that there's a better (and workgin) way to get the subdocument of a fetched document.

有什么想法吗?

PS:我解决了使用for"循环检查 data.permission 数组中的每个项目并检查 data.permissions[i]._id == permission._id 但我想要一个更智能的解决方案,我知道有一个!

推荐答案

正如您所注意到的,mongoose 的默认设置是,当您将数据嵌入"到这样的数组中时,您会得到一个 _id每个数组条目的值作为其自己的子文档属性的一部分.您实际上可以使用此值来确定要更新的项目的索引.MongoDB 这样做的方法是 positional $ 操作符变量,它保存数组中匹配"的位置:

So as you note, the default in mongoose is that when you "embed" data in an array like this you get an _id value for each array entry as part of it's own sub-document properties. You can actually use this value in order to determine the index of the item which you intend to update. The MongoDB way of doing this is the positional $ operator variable, which holds the "matched" position in the array:

Folder.findOneAndUpdate(
    { "_id": folderId, "permissions._id": permission._id },
    { 
        "$set": {
            "permissions.$": permission
        }
    },
    function(err,doc) {

    }
);

.findOneAndUpdate() 方法将返回修改后的文档或否则,如果您不需要返回的文档,您可以使用 .update() 作为方法.主要部分是匹配"要更新的数组元素和识别"与 positional 匹配的元素$ 如前所述.

That .findOneAndUpdate() method will return the modified document or otherwise you can just use .update() as a method if you don't need the document returned. The main parts are "matching" the element of the array to update and "identifying" that match with the positional $ as mentioned earlier.

那当然你正在使用 $set 运算符,以便您指定的元素实际上通过网络"发送到服务器.您可以使用 "dot notation" 更进一步,只需指定您实际使用的元素想更新.如:

Then of course you are using the $set operator so that only the elements you specify are actually sent "over the wire" to the server. You can take this further with "dot notation" and just specify the elements you actually want to update. As in:

Folder.findOneAndUpdate(
    { "_id": folderId, "permissions._id": permission._id },
    { 
        "$set": {
            "permissions.$.role": permission.role
        }
    },
    function(err,doc) {

    }
);

这就是 MongoDB 提供的灵活性,您可以非常有针对性"地实际更新文档.

So this is the flexibility that MongoDB provides, where you can be very "targeted" in how you actually update a document.

然而,这样做的作用是绕过"您可能已内置到猫鼬"模式中的任何逻辑,例如验证"或其他预保存挂钩".那是因为最佳"方式是 MongoDB 的功能"及其设计方式.Mongoose 本身试图成为这个逻辑的便利"包装器.但是,如果您准备自己进行一些控制,那么可以以最佳方式进行更新.

What this does do however is "bypass" any logic you might have built into your "mongoose" schema, such as "validation" or other "pre-save hooks". That is because the "optimal" way is a MongoDB "feature" and how it is designed. Mongoose itself tries to be a "convenience" wrapper over this logic. But if you are prepared to take some control yourself, then the updates can be made in the most optimal way.

因此,在可能的情况下,请保持数据嵌入"状态,不要使用引用模型.它允许在不需要担心并发性的简单更新中对父"和子"项进行原子更新.可能是您应该首先选择 MongoDB 的原因之一.

So where possible to do so, keep your data "embedded" and don't use referenced models. It allows the atomic update of both "parent" and "child" items in simple updates where you don't need to worry about concurrency. Probably is one of the reasons you should have selected MongoDB in the first place.

这篇关于Mongoose 查找/更新子文档的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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