如何只获取mongoose中的“唯一”子子文档,删除重复项?

时间:2016-03-14 10:41:00

标签: node.js mongodb mongoose mongoose-schema

我是mongodb&的新手mongoose,我在mongoose文档中搜索的越多,我就越迷失 假设我有一个user name字段的值为 John ,John有两个role s:

  • 超级用户
  • 管理

role中的每一个都有一些permissions

  • 超级用户
    • addQuestion
    • editQuestion
    • removeQuestion
  • 管理
    • addQuestion
    • viewAnswer

如您所见,每个role都有重复项,如何在没有重复项的数组中获得用户 John 的权限(此示例中重复的一个是{{1} }),像这样:

['addQuestion','editQuestion','removeQuestion','viewAnswer']

这是我的架构:

addQuestion

如您所见,我在var mongoose = require('mongoose'); var Schema = mongoose.Schema; var deepPopulate = require('mongoose-deep-populate')(mongoose); var UserSchema = new Schema({ name: String, user_roles: [{ type: Schema.ObjectId, ref: 'Role' }] }); var RoleSchema = new Schema({ name: String, permissions: [ { type: Schema.ObjectId, ref: 'Permission' } ] }); var PermissionSchema = new Schema({ name: String }); UserSchema.plugin(deepPopulate, { whitelist: ['user_roles.permissions'] }); var User = mongoose.model('User', UserSchema), Role = mongoose.model('Role', RoleSchema), Permission = mongoose.model('Permission', PermissionSchema); 数组中没有权限名称,我有引用(permissions s)。

我只有来自网址的ObjectId。 这样:

userId

我应该使用User.findById(userId) .deepPopulate('user_roles') .deepPopulate('user_roles.permissions') .distinct('permissions') .distinct('user_roles.permissions') .exec((err, user)=> { if(err) res.send(err); ???? res.json(permissionsArr); }); 吗? 我可以在没有distinct的情况下使用distinct吗?还是必须的? 或者代替populate我应该使用传入回调的distinct项而不是user使用????参数(使用user方法)获取所有角色,并为所有角色获取权限,然后从find数组中删除重复项?

更新:这是使用mongoose进行休息api的结果,获取用户角色(GET http://localhost/api/users/:userId/roles):

permissionsArr

结果:

app.get('/api/users/:userId/roles', function(req,res) {
    User.findById( req.params.userId )
        .deepPopulate('user_roles.permissions')
        .select('user_roles')
        .exec((err, users)=> {
            if(err) next(err);
            res.json(users);
        });
}

现在我需要的是{ "name": "John", "_id": "56e677c1a7e7007d5cc245ef", "user_roles": [ { "_id": "56e64f057e8008263dec2cc9", "name": "superuser", "permissions": [ { "name": "removeQuestion", "_id": "56e408a9d863a8cf4d7ab001" }, { "name": "addQuestion", "_id": "56e64d657e8008263dec2cc4" }, { "name": "addAnswer", "_id": "56e64cf87e8008263dec2cc3" }, { "name": "viewQuestion", "_id": "56e64e1e7e8008263dec2cc5" }, { "name": "viewAnswer", "_id": "56e64e267e8008263dec2cc6" } ] }, { "_id": "56e64ec27e8008263dec2cc8", "name": "admin", "permissions": [ { "name": "addQuestion", "_id": "56e64d657e8008263dec2cc4" }, { "name": "addAnswer", "_id": "56e64cf87e8008263dec2cc3" }, { "name": "viewQuestion", "_id": "56e64e1e7e8008263dec2cc5" }, { "name": "viewAnswer", "_id": "56e64e267e8008263dec2cc6" } ] } http://localhost/api/users/:userId/permissions以及获取用户拥有的GET的{​​{1}},但删除了重复项。({ {1}}不应直接permissions。)

感谢您的时间和任何您能提供的帮助。

2 个答案:

答案 0 :(得分:1)

在使用您的架构测试某些代码后,我发现.distinct只是user_roles的值,而不是populate的结果,例如user_roles.permissions。这可能是填充过滤用户结果后删除重复permissions的一种方法。

User.findById('56e7b1f74e7192381adbfdbc')
    .populate({
        path: 'user_roles',
        model: 'Role',
        populate: {
            path: 'permissions',
            model: 'Permission'         
        }
    })
    .exec(function(err, user) {
        if (err)
            console.log(err);
        else {
            //console.log(util.inspect(user, { showHidden: true, depth: null }));

            var s = new Set();
            // remove duplicate permission 
            user.user_roles.forEach(function(u){
                u.permissions.forEach(function(p) {
                    s.add(p.name);
                })
            })

            var arr = [...s]; // convert set to array
            console.log(arr);
        }
    });

顺便说一句,您可以在不使用模块mongoose-deep-populate的情况下以这种方式填充结果。

答案 1 :(得分:0)

实际上,您可以使用聚合框架重复删除嵌套的权限数组。您还可以选择map-reduce,但建议使用聚合框架,并且性能更高。

db.users.aggregate([
    {$match:{_id:"56e677c1a7e7007d5cc245ef"}},
    {$unwind:"$user_roles"},
    {$unwind:"$user_roles.permissions"},
    {$group:{_id:"$_id", permissions:{$addToSet:"$user_roles.permissions.name"}}}
])

根据您的示例文档,它应该提取

{ 
    "_id" : "56e677c1a7e7007d5cc245ef", 
    "permissions" : [
        "addAnswer", 
        "viewAnswer", 
        "viewQuestion", 
        "addQuestion", 
        "removeQuestion"
    ]
}

我很肯定你可以把它翻译成猫鼬,而且很容易。