如何通过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操作符组合过滤$projectpipe道中的数组元素。

$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});