【问题标题】:MongoDB query multiple subdocumentsMongoDB查询多个子文档
【发布时间】:2020-07-10 03:31:23
【问题描述】:

我的 MongoDB 数据结构如下所示:

{
  users: [{
    userref: "User1",
    results: [{
      testref: "TEST1",
      history: [{
        score: 10
      }, {
        score: 15
      }]
    }, {
      testref: "TEST2",
      history: [{
        score: 2
      }, {
        score: 1
      }]
    }]
  }]
}

我有一组用户,每个用户都有一组结果(每个测试一个结果对象),并且在每个结果中,有一组历史分数的历史记录。

我需要做的是“返回 TEST1 的最新分数为 X 且 TEST2 的最新分数为 Y 的所有用户的 userref”。未完成其中一项或多项测试的用户不应被退回。 “最近的”是指数组中的最后一个。

我假设我需要使用聚合,但我对此完全陌生,所以可以通过一些帮助来做。

这是我迄今为止尝试过的,它有效,但它只匹配TEST1 = 15的条件,我也希望它匹配条件TEST2 = 1。

[{$unwind: {
  path: '$results’,
  preserveNullAndEmptyArrays: false
}}, {$match: {
  'results.testref': 'TEST1'
}}, {$project: {
  results: 1,
  userref: 1,
}}, {$replaceRoot: {
  newRoot: {
    $mergeObjects: [
      {
        userref: '$userref'
      },
      '$results'
    ]
  }
}}, {$project: {
  userref: 1,
  history: {
    $slice: [
      '$history',
      -1
    ]
  }
}}, {$match: {
  'history.score': 15
}}, {$project: {
  userref: 1,
}}]

谢谢

【问题讨论】:

  • 你试过了吗?根据您的数据,recent 是什么意思?
  • 谢谢@Gibbs,我已经添加了更多细节和我已经开始的聚合。这对我来说似乎很笨重,所以我相信有更好的方法来做到这一点。 “最近的”是指历史数组中的最后一个条目。

标签: mongodb aggregation-framework


【解决方案1】:

要同时满足这两个条件,

db.getCollection('test2').aggregate([{"$unwind":"$users"}, {$unwind:"$users.results"}, 
{$project:
     {"lastScore": 
        {$slice:
            ["$users.results.history", -1]
        },
     "users.userref":1,
     "users.results.testref":1
    }
},
{
    $match:{"$or":[{
      $and:[
        {"users.results.testref":"TEST1"},
        {"lastScore.0.score":15}
      ]},
      {
      $and:[
        {"users.results.testref":"TEST2"},
        {"lastScore.0.score":1}
      ]}
      ]
    }
},
{
    $group:{
        "_id":{"_id":"$_id","userref":"$users.userref"},
        "data":{$push:{"tests":"$users.results.testref", "userref":"$users.userref"}}
    }
},
{
    $project:{
        "_id":1,
        "validUser":{
        "$filter":{
            "input":"$data",
            "as":"data",
            "cond":{$or:[{$eq:["$$data.tests","TEST1"]}, {$eq:["$$data.tests","TEST2"]}]}
        }}
    }
},
{
    $project:{
        "_id.userref":1
    }
}
])

查询的作用:

  1. 放松用户
  2. 展开结果
  3. 获取最后分数部分以及用户参考,测试参考
  4. 检查必要条件
  5. 在用户 ref 和 doc id 上分组
  6. 使用 $filte 检查两个条件是否满足
  7. 项目用户参考

输出:

/* 1 */
{
    "_id" : {
        "userref" : "User1"
    }
}

【讨论】:

  • 这是一个巨大的帮助,非常感谢您抽出宝贵的时间。我做了一些小调整:事实上,过滤器返回完成了其中一个测试的任何用户,我需要它只返回那些完成了两个测试的用户,所以我将它更改为 $match : {$and: [ {"data": {$elemMatch: {tests: "CONF"}}}, {"data": {$elemMatch: {tests: "PB"}}} ]}。最后我还做了一个 $replaceRoot { newRoot: { userref: '$_id.userref' } } 以摆脱 userref 的 _id 容器。没有你的眼睛会挣扎很长时间,谢谢@Gibbs。
  • 很高兴,它有帮助。快乐编码@EricP
猜你喜欢
  • 2017-10-01
  • 1970-01-01
  • 2017-01-04
  • 1970-01-01
  • 1970-01-01
  • 2016-09-29
  • 1970-01-01
  • 1970-01-01
  • 2018-09-04
相关资源
最近更新 更多