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