【问题标题】:how to filter by schema property in mongoose如何在猫鼬中按模式属性进行过滤
【发布时间】:2017-01-03 17:28:36
【问题描述】:

我有一个group 对象,其中包含一个members 属性。 members 属性是一个对象数组。该对象具有以下属性。

{"id" : "1", "status" : 1}

我的要求是获取给定group 对象(通过给定ID)的状态为1 的用户列表。

这是可以做到的,只需通过简单的 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"});

提前谢谢你。

【问题讨论】:

  • 您是指给定的 group 对象而不是 post 对象吗?
  • 与其给出 Schema 定义,不如分享一些示例文档和预期的输出,这样很容易理解您要完成的工作。
  • @chridam group 对象。编辑了问题。
  • @suzo 我的预期结果是一组成员,他们的状态为一。
  • 你能检查我的答案并告诉我这是否是你所期望的吗?

标签: node.js mongodb mongoose mongodb-query aggregation-framework


【解决方案1】:

您可以使用聚合框架通过给定的组 id 和成员数组状态字段过滤组集合中的文档。这将是您的初始管道阶段,由 $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);
    });
});

【讨论】:

  • @sacDahal 它通过对同一数据库中的未分片集合执行“左外连接”来过滤来自“已连接”集合的文档以进行处理。 $lookup 阶段在来自输入文档的字段与来自“已加入”集合的文档的字段之间进行相等匹配。有时$lookup 可能会被误用于将 MongoDB 视为关系数据库,但开发人员应该知道何时使用它是合适的,何时是反模式。
  • 看起来我的 mongoDB 版本与 $filter 管道阶段不兼容。还有其他可能的阶段我们可以用来代替$filter
  • 您的 MongoDB 和 Mongoose 版本是什么?
  • @ErangaKapukotuwa 我添加了一个解决方法,试一试,如果可行,请告诉我。
【解决方案2】:

假设你的收藏名称是groups,你可以这样查询:

db.groups.find({"members.status":1}, {"members":1});

这将获取所有状态为 1 的用户。如果您想根据特定的 user_id 进行查询(假设用户 id 为“1A”),您可以像这样添加对象:

db.groups.find({"members.status":1, "members.user_id":"1A"}, {"members":1});

【讨论】:

    猜你喜欢
    • 2021-12-23
    • 1970-01-01
    • 1970-01-01
    • 2017-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-12
    • 2019-12-29
    相关资源
    最近更新 更多