Node.js mongoose中如何按模式属性过滤
我有一个Node.js mongoose中如何按模式属性过滤,node.js,mongodb,mongoose,mongodb-query,aggregation-framework,Node.js,Mongodb,Mongoose,Mongodb Query,Aggregation Framework,我有一个组对象,它包含一个成员属性。members属性是一个对象数组。该对象具有以下属性 {"id" : "1", "status" : 1} 我的要求是获取给定组对象的状态为1的用户列表(通过给定id) 通过一个简单的get by ID查询和一个foreach,就可以做到这一点。但我想知道,是否有任何预先查询可以做到这一点 我的团队目标如下 var UserSchema = new Schema({ user_id:{ type : Schema.ObjectId, re
组
对象,它包含一个成员
属性。members
属性是一个对象数组。该对象具有以下属性
{"id" : "1", "status" : 1}
我的要求是获取给定组
对象的状态为1
的用户列表(通过给定id)
通过一个简单的get by 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"});
提前谢谢。假设您的收藏名称为
组
,您可以这样查询:
db.groups.find({"members.status":1}, {"members":1});
这将获取状态为1的所有用户。如果要基于特定的用户id(此处假设用户id为“1A”)进行查询,可以添加如下对象:
db.groups.find({"members.status":1, "members.user_id":"1A"}, {"members":1});
您可以使用聚合框架根据给定的组id和成员数组状态字段筛选groups集合中的文档。这将是您的初始管道阶段,由操作员驱动 下一个管道步骤应该是操作符,它根据给定条件选择成员数组的子集。这是必要的,因为之前的管道仅在文档级别进行过滤,而不是在数组/字段级别进行过滤 获得过滤后的数组后,可以应用函数作为“填充”成员列表的方法。但是,由于
localField
是一个数组,您希望将其中的元素与foreignField
进行匹配,后者是单个元素,因此在应用操作符之前,您需要将数组作为聚合管道的一个阶段进行匹配
以下示例演示如何在您的案例中应用上述所有步骤:
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中引入的和运算符。x和更新,然后考虑使用<强> < /强>和<强> < /强>运算符组合来过滤<强> <强>管道中的数组元素。 操作符本质上创建了一个新的数组字段,该字段保存数组中每个元素的子表达式中计算逻辑的结果值。然后,运算符返回一个集合,其中的元素出现在第一个集合中,但不出现在第二个集合中;i、 e.执行第二组相对于第一组的相对补码。在这种情况下,它将通过
status
属性返回最终成员数组,该数组包含与父文档不相关的元素
在管道步骤之后执行聚合操作,由于返回的文档是纯javascript对象,而不是(可以返回任何形状的文档),因此需要将结果强制转换为,以便在字段上使用填充函数来填充结果
以下示例演示了上述解决方法:
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);
});
});
您是指一个给定的组对象而不是post对象吗?与其给出架构定义,不如共享一些示例文档和预期的输出,这样就可以很容易地理解您要完成的任务。@chridam
group
object。编辑了该问题。@suzo我的预期结果是一组状态为1的成员。您能检查我的答案并告诉我这是否是您所期望的吗?@sacDahal它的工作原理是对同一数据库中的未归档集合执行“左外部联接”,以筛选“联接”集合中的文档进行处理。$lookup
阶段在输入文档中的字段与“联接”集合中的文档中的字段之间进行相等匹配。有时,$lookup
可能被错误地用于将MongoDB视为关系数据库,但开发人员应该知道何时使用它是合适的,何时它是反模式的。看起来我的MongoDB版本与$filter
管道阶段不兼容。有没有其他可能的阶段可以用来替换$filter
。你的MongoDB和Mongoose版本是什么?@ErangaKapukotuwa我已经添加了一个解决方案,试试看,如果可行的话请告诉我。