我有两个MongoDB模型和#34;用户"和#34;角色"。每个用户可以拥有多个角色,每个角色都可以分配给许多用户。为了保持关系简单,我想在两个模型中仅存储"用户"已按预期工作的模型。但是当我使用.find({})一次加载所有角色时,我还想知道有多少用户被分配到这些角色(以检查是否可以修改角色)。
我使用Node.js + ExpressJS和mongoose。这就是我已经拥有的:
var userSchema = new Schema({
username: String,
...
roles : [ {
type : Number,
ref : 'Role'
} ]
});
var roleSchema = new Schema({
_id : Number,
name : String
});
--------------------------------------------------
function getRoles(request, response) {
Role.find({}, function(err, roles) {
....
response.send(roles);
});
}
但现在我想知道如何在每个角色中执行计数查询,并且仍然能够在一个响应中发送结果。
我想避免为每个角色发送一个请求,并尝试在getRoles()函数中进行计数。在关系数据库中,我会做这样的事情:
select r.*,
(select count(*) from user2role u2r where u2r.role_id = r.role_id)
from role r;
但MongoDB的等价物是什么?
任何帮助和提示都将不胜感激。
谢谢,格里
答案 0 :(得分:0)
根据您对架构设计的上述说明,我可以假设您的架构如下:
角色集合:
{
role_id :
name :
}
用户收藏:
{
user :
role_id : [ ]
....
}
您可以使用聚合来实现此目的:
db.users.aggregate([{$unwind: "$role_id"},
{$group: {_id: "$role_id", count : {"$sum":1}} },
]);
答案 1 :(得分:0)
要使用给定架构实现每个角色的用户计数查询,您可以使用 count()
方法,如下所示:
function getUsersCount(roleName, req, res) {
Role.findOne({"name": roleName}, function(err, role) {
var roleId = role._id;
// var countQuery = User.where({ "role": roleId }).count();
// User.count({ "roles": roleId }).count(callback)
// User.count({ "roles": roleId }, callback)
User.where({ "roles": roleId }).count(function (err, count) {
if (err) return handleError(err);
console.log("There are %d users with the role %d", count, roleName);
res.send(count);
})
});
}
或者您可以使用 aggregate()
方法,例如:
// Find the user count for a given role
function getUsersCount(roleName, req, res) {
Role.findOne({"name": roleName}, function(err, role) {
var roleId = role._id;
var pipeline = [
{
"$match": { "roles": roleId } /* filter the documents that only have the roleId in the role array */
},
{ "$unwind": "$roles" },
{
"$match": { "roles": roleId }
},
{
"$group": {
"_id": null, "count": { "$sum": 1 }
}
},
{
"$project": {
"_id": 0, "count": 1
}
}
];
Users.aggregate(pipeline, function (err, result) {
if (err) return handleError(err);
console.log(result); // [ { count: 55 } ] for example
res.send(result);
});
// Or use the aggregation pipeline builder.
Users.aggregate()
.match({ "roles": roleId })
.unwind("roles")
.match({ "roles": roleId })
.group({ "_id": null, "count": { "$sum": 1 } })
.select("-id count")
.exec(function (err, result) {
if (err) return handleError(err);
console.log(result); // [ { count: 55 } ] for example
res.send(result);
});
});
}
- 编辑 -
您可以采用的一种方法是使用 lean()
方法获取可以操作的纯JavaScript对象,以便为每个角色添加额外的userCount
字段。使用 lean()
是可能的,因为启用了精益选项的查询返回的文档是普通的javascript对象,而不是 MongooseDocuments 。因此,使用从 find()
游标返回的角色,您可以将它们转换为纯JS对象
您可以使用原生JavaScript map()
方法进行迭代,使用另一个考虑 count()
的查询获取每个角色的用户数上面解释的方法并返回修改后的对象。
以下演示了如何实现该功能:
function getRoles(request, response) {
Role.find({}).lean().exec(function(err, roles) {
var result = roles.map(function(r){
var obj = {},
countQuery = User.where({ "roles": r._id }).count();
obj["userCount"] = countQuery;
obj["_id"] = r._id;
obj["name"] = r.name;
return obj;
});
response.send(result);
});
}