Mongoose查找/更新子文档
Mongoose find/update subdocument
我有以下文档架构文件夹:
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中有一个面板,我在其中列出了所有文件夹及其权限。管理员可以编辑并保存单个权限。
我可以很容易地保存整个文件夹文档及其权限数组,其中只有一个权限被修改。但我不想保存所有的文档(真正的模式有更多的字段),所以我这样做了:
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总是未定义!我尝试以这种方式"静态"获取权限:
var perm = data.permissions[0];
而且它工作得很好,所以问题是Undercore库无法查询权限数组。因此,我想有一种更好的(也是可行的)方法来获取提取文档的子文档。
知道吗?
p。S.:我解决了使用"for"循环检查data.permission数组中的每个项并检查data.premissions[I]_id=permission的问题_id,但我想要一个更聪明的解决方案,我知道有一个
因此,正如您所注意到的,mongoose中的默认值是,当您像这样将数据"嵌入"到数组中时,您会为每个数组条目获得一个_id
值,作为其自身子文档属性的一部分。实际上,您可以使用此值来确定要更新的项目的索引。MongoDB实现这一点的方法是位置$
操作符变量,它保存数组中的"匹配"位置:
Folder.findOneAndUpdate(
{ "_id": folderId, "permissions._id": permission._id },
{
"$set": {
"permissions.$": permission
}
},
function(err,doc) {
}
);
.findOneAndUpdate()
方法将返回修改后的文档,否则,如果不需要返回文档,则可以使用.update()
作为方法。主要部分是"匹配"要更新的数组元素,以及"识别"与前面提到的位置$
匹配的元素。
然后,您当然要使用$set
运算符,以便只有您指定的元素实际通过"有线"发送到服务器。您可以通过"点表示法"进一步了解这一点,只需指定您实际想要更新的元素。如:
Folder.findOneAndUpdate(
{ "_id": folderId, "permissions._id": permission._id },
{
"$set": {
"permissions.$.role": permission.role
}
},
function(err,doc) {
}
);
因此,这就是MongoDB提供的灵活性,在如何实际更新文档时,您可以非常"有针对性"。
然而,它所做的是"绕过"您可能已经构建到"猫鼬"模式中的任何逻辑,例如"验证"或其他"预保存挂钩"。这是因为"最佳"方式是MongoDB的"特性"及其设计方式。Mongoose本身试图成为这个逻辑的"方便"包装器。但是,如果你准备好自己进行一些控制,那么更新可以以最优化的方式进行。
因此,在可能的情况下,保持数据"嵌入",不要使用引用的模型。它允许在不需要担心并发性的简单更新中对"父"answers"子"项进行原子更新。这可能是您应该首先选择MongoDB的原因之一。
为了在Mongoose中更新时验证子文档,您必须将其作为Schema对象"加载",然后Mongoose将自动触发验证和挂钩。
const userSchema = new mongoose.Schema({
// ...
addresses: [addressSchema],
});
如果您有一个子文档数组,您可以使用Mongoose提供的id()
方法获取所需的子文档。然后可以单独更新其字段,或者如果要同时更新多个字段,则使用set()
方法。
User.findById(userId)
.then((user) => {
const address = user.addresses.id(addressId); // returns a matching subdocument
address.set(req.body); // updates the address while keeping its schema
// address.zipCode = req.body.zipCode; // individual fields can be set directly
return user.save(); // saves document with subdocuments and triggers validation
})
.then((user) => {
res.send({ user });
})
.catch(e => res.status(400).send(e));
请注意,您并不真正需要userId
来查找User文档,您可以通过搜索具有与addressId
匹配的地址子文档来获得它,如下所示:
User.findOne({
'addresses._id': addressId,
})
// .then() ... the same as the example above
请记住,在MongoDB中,子文档只有在保存父文档时才保存。
阅读官方文档中有关该主题的更多信息。
如果您不想要单独的集合,只需将permissionSchema嵌入到folderSchema中即可。
var folderSchema = new Schema({
name: { type: string },
permissions: [ {
role: { type: String },
create_folders: { type: Boolean },
create_contents: { type: Boolean }
} ]
});
如果您需要单独收集,这是最好的方法:
你可以有一个权限模型:
var mongoose = require('mongoose');
var PermissionSchema = new Schema({
role: { type: String },
create_folders: { type: Boolean },
create_contents: { type: Boolean }
});
module.exports = mongoose.model('Permission', PermissionSchema);
以及具有对权限文档的引用的文件夹模型。您可以引用另一个类似的模式:
var mongoose = require('mongoose');
var FolderSchema = new Schema({
name: { type: string },
permissions: [ { type: mongoose.Schema.Types.ObjectId, ref: 'Permission' } ]
});
module.exports = mongoose.model('Folder', FolderSchema);
然后调用Folder.findOne().populate('permissions')
请求mongoose填充字段权限。
现在,以下内容:
savePermission: function (folderId, permission, callback) {
Folder.findOne({ _id: folderId }).populate('permissions').exec(function (err, data) {
var perm = _.findWhere(data.permissions, { _id: permission._id });
_.extend(perm, permission);
data.markModified("permissions");
data.save(callback);
});
}
perm
字段不会未定义(如果permission_id实际上在permissions数组中),因为它是由Mongoose填充的。
只需尝试
let doc = await Folder.findOneAndUpdate(
{ "_id": folderId, "permissions._id": permission._id },
{ "permissions.$": permission},
);
- 流星收集更新不是在更新文档
- 使用猫鼬更新子文档
- MongoDB findAndModify:>>>查找和更新文档数组中的对象
- Javascript 不会在浏览器中更新文档
- 更新数组中的嵌入文档 - Mongodb + Node Driver
- 如何在猫鼬中更新文档后添加一些操作
- Mongodb 嵌套文档更新
- 检查文档是否已经存在,如果是则更新,否则创建新的Mongoose
- 如何在更新mongo文档时使用变量
- 在更新选择器中使用$in时颠倒多个文档
- 编辑以前保存的文档也会更新数据库中的文档
- 使用mongodb更新多个文档
- Mongoose创建一个文档,如果找不到指定的字段,则更新文档中的数组
- Meteor Update集合-未捕获错误:不允许.不受信任的代码只能通过ID更新文档.[403]
- Mongo-shell游标:更新后的文档再次到达游标
- 在MongoDB中获取“更新前”文档
- 数组中嵌入文档的集合更新属性
- 如何将一些参数从javascript接收响应字符串 asp.net 页面并更新html文档
- 如何从 MongoDB 文档更新与特定值匹配的数组
- 猫鼬嵌入文档更新