如何通过mongoose中的模式属性进行过滤
我有一个group
对象,它包含一个members
属性。 members
属性是一个对象数组。 该对象具有以下属性。
{"id" : "1", "status" : 1}
我的要求是获得给定group
对象的状态为1
的用户列表(通过给定的ID)。
这是可能做到的,用一个简单的ID查询和一个foreach
。 但是想知道,是否有任何提前查询来做到这一点。
我的整体组对象如下。
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"});
先谢谢你。
您可以使用聚合框架按给定的组ID和成员数组状态字段过滤组合中的文档。 这将是您的初始pipe道阶段,这是$match
运算符驱动的。
下一个pipe道步骤应该是$filter
操作符,它根据给定的条件select成员数组的一个子集。 这是必要的,因为前一个stream水线只能在文档级进行过滤,而不能在数组/现场级进行过滤。
一旦你得到了过滤的数组,你可以应用$lookup
函数来“填充”你的成员列表。 但是,由于localField
是一个数组,并且想要将其中的元素与作为单个元素的foreignField
进行匹配,所以在应用$lookup
运算符之前,需要将数组展开为聚合stream水线的一个阶段。
以下示例演示了如何在您的案例中应用上述所有步骤:
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
pipe道中的数组元素。
$map
操作符实质上创build了一个新的数组字段,该数组字段将值作为评估逻辑的结果保存在数组的每个元素的子expression式中。 $setDifference
操作符然后返回一个集合,其中元素出现在第一个集合中,但不在第二个集合中; 即相对于第一组执行第二组的相对补充。 在这种情况下,它将通过status
属性返回具有与父文档无关的元素的最终成员数组。
执行$project
pipeline步骤之后的聚集操作,并且由于返回的文档是纯javascript对象,而不是Mongoose Documents (可以返回任何forms的文档),所以需要将结果转换为Mongoose文档,以便您可以使用填充函数结果的领域。
以下示例演示了上述解决方法:
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); }); });
假设你的集合名称是groups
,你可以这样查询:
db.groups.find({"members.status":1}, {"members":1});
这将获取状态为1的所有用户。如果您想基于特定的user_id进行查询(假设此处的用户标识为“1A”),则可以像这样添加对象:
db.groups.find({"members.status":1, "members.user_id":"1A"}, {"members":1});