我有一个group
对象,其中包含members
属性。 members
属性是一个对象数组。该对象具有以下属性。
{"id" : "1", "status" : 1}
我的要求是获取给定1
个对象(按给定ID)的状态为group
的用户列表。
这可以通过简单的ID by get查询和foreach
来实现。但是想知道,是否有任何提前查询要做到这一点。
我的整体Group对象如下。
var UserSchema = new Schema({
user_id:{
type : Schema.ObjectId,
ref : 'User',
default : null
},
status:{
type : Number,
default : null /* 1 - pending | 2 - rejected | 3 - accepted*/
},
});
var GroupSchema = new Schema({
type:{
type : Number,
default : 1 /* 1 - group | 2 - community*/
},
name:{
type:String,
default:null
},
members:[UserSchema]
},{collection:"groups"});
提前谢谢你。
答案 0 :(得分:2)
您可以使用聚合框架按给定的组ID和成员数组状态字段筛选groups集合中的文档。这将是您的初始管道阶段, $match
由运营商驱动。
下一个管道步骤应该是 $filter
运算符,它根据给定条件选择成员数组的子集。这是必要的,因为前一个管道只在文档级别过滤,而不是在数组/字段级别过滤。
获得已过滤的数组后,您可以应用 $lookup
功能作为“填充”您的成员列表的方法。但是,由于localField
是一个数组,并且您希望将其中的元素与foreignField
(单个元素)进行匹配,因此您需要 $unwind
在应用 $lookup
运算符之前,数组作为聚合管道的一个阶段。
以下示例演示了如何在您的案例中应用上述所有步骤:
Group.aggregate([
{
"$match": {
"_id": groupId,
"members.status": 1
}
},
{
"$filter": {
"input": "$members",
"as": "member",
"cond": { "$eq": ["$$member.status", 1] }
}
}
{ "$unwind": "$members" },
{
"$lookup": {
"from": "users"
"localField": "members.user_id",
"foreignField": "_id",
"as": "member"
}
}
]).exec(function(err, results) {
if (err) throw err;
console.log(results);
});
结果将包含具有组和用户属性的文档列表。
如果您的MongoDB版本不支持版本3.2中引入的 $filter
和 $lookup
运算符。 X和更新版本,然后考虑使用 $setDifference
和 $map
运算符组合来过滤 $project
中的数组元素管道。
$map
运算符本质上创建了一个新的数组字段,该字段在子表达式中对数组的每个元素进行评估逻辑时保存值。 $setDifference
运算符然后返回一个集合,其中的元素出现在第一个集合中但不出现在第二个集合中;即执行第二组相对于第一组的相对补码。在这种情况下,它将通过status
属性返回包含与父文档无关的元素的最终成员数组。
在 $project
管道步骤之后执行聚合操作,因为返回的文档是普通的javascript对象,而不是Mongoose Documents(可以返回任何形状的文档),你需要将结果转换为Mongoose Documents,以便您可以在字段上使用结果的填充函数。
以下示例演示了上述解决方法:
Group.aggregate([
{
"$match": {
"_id": groupId,
"members.status": 1
}
},
{
"$project": {
"type": 1, "name": 1,
"members": {
"$setDifference": [
{
"$map": {
"input": "$members",
"as": "member",
"in": {
"$cond": [
{ "$eq": [ "$$member.status", 1 ] },
"$$member",
false
]
}
}
},
[false]
]
}
}
}
]).exec(function(err, result) {
if (err) throw err;
var docs = result.map(function(doc) { return new Group(doc) });
Group.populate(docs, { "path": "members" }, function(err, results) {
if (err) throw err;
console.log(JSON.stringify(results, undefined, 4 ));
res.json(results);
});
});
答案 1 :(得分:0)
假设您的收藏名称为groups
,您可以这样查询:
db.groups.find({"members.status":1}, {"members":1});
这将获取具有状态1的所有用户。如果要基于特定的user_id进行查询(假设用户ID为&#34; 1A&#34;此处),则可以添加如下对象:< / p>
db.groups.find({"members.status":1, "members.user_id":"1A"}, {"members":1});