mongoosefind/更新子文档

我有以下模式的文件

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中有一个面板,我列出了所有的文件夹和他们的权限。 pipe理员可以编辑一个权限并保存。

我可以使用其权限数组轻松地保存整个文件夹文档,其中只有一个权限被修改。 但我不想保存所有的文档(真正的模式有更多的字段),所以我这样做:

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

但问题是, 烫发总是未定义的 ! 我试图以这种方式“静态”获取权限:

 var perm = data.permissions[0]; 

它工作得很好,所以问题在于Underscore库不能查询权限数组。 所以我想,有一个更好的(和工作)的方式来获取文件的子文档。

任何想法?

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

正如你所注意到的,mongoose中的默认值是当你像这样在数组中embedded数据时,每个数组项的_id值作为它自己的子文档属性的一部分。 您实际上可以使用此值来确定您要更新的项目的索引。 这样做的MongoDB的方式是位置$运算符variables,它保存在数组中的“匹配”的位置:

 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提供的灵活性,在这里你可以非常有针对性地知道如何实际更新文档。

但是,它所做的是“绕过”可能已经内置到“mongoose”模式中的任何逻辑,例如“validation”或其他“预保存钩子”。 这是因为“最优”的方式是一个MongoDB的“function”,它是如何devise的。 mongoose本身试图成为这个逻辑的“便利”包装。 但是,如果你准备好自己控制一下,那么更新可以以最优化的方式进行。

因此,在可能的情况下,保持数据“embedded”,不要使用参考模型。 它允许简单更新中的“父”和“子”项的primefaces更新,您不必担心并发性。 可能是你首先selectMongoDB的原因之一。

如果您不想单独收集,只需将permissionSchemaembedded到folderSchema中即可。

 var folderSchema = new Schema({ name: { type: string }, permissions: [ { role: { type: String }, create_folders: { type: Boolean }, create_contents: { type: Boolean } } ] }); 

如果你需要单独的collections,这是最好的方法:

你可以有一个权限模式:

 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填充了。