【问题标题】:MongoDB: Get count of inner array object with nested array element matchMongoDB:获取具有嵌套数组元素匹配的内部数组对象的计数
【发布时间】:2020-04-27 09:21:02
【问题描述】:

我有 mongo 集合,其中包含每个用户提交的调查答案。我想获得选择作为选项的用户数。只有一位用户选择了选项 O12。输出应该是 1。

{
    "_id" : ObjectId("5ea179eb39ff117948f19266"),
    "_class" : "model.survey.Answer",
    "survey_id" : "5ea178c239ff117948f19265",
    "survey_user" : [ 
        {
            "user_id" : 1072,
            "user_option" : [ 
                {
                    "question_id" : "Q1",
                    "option_id" : "O11"
                }, 
                {
                    "question_id" : "Q2",
                    "option_id" : "O21"
                }, 
                {
                    "question_id" : "Q3",
                    "option_id" : "O31"
                }, 
                {
                    "question_id" : "Q4",
                    "option_id" : "O41"
                }
            ]
        }, 
        {
            "user_id" : 1073,
            "user_option" : [ 
                {
                    "question_id" : "Q1",
                    "option_id" : "O12"
                }, 
                {
                    "question_id" : "Q2",
                    "option_id" : "O21"
                }, 
                {
                    "question_id" : "Q3",
                    "option_id" : "O31"
                }, 
                {
                    "question_id" : "Q4",
                    "option_id" : "O41"
                }
            ]
        }
    ]
}

【问题讨论】:

    标签: spring mongodb aggregation-framework mongotemplate


    【解决方案1】:

    您可以使用 MongoDB 的 aggregation-pipeline 来做到这一点:

    不同的方法,一种方法是使用$unwind

    类型 1 - 查询 1:

    db.collection.aggregate([
        /** Optional but will be good on huge collections to lessen data for further stages */
        {
          $match: { "survey_user.user_option.option_id": "O12" }
        },
        {
          $unwind: "$survey_user"
        },
        /** When you unwind a each object/element in array gets it's own document after `unwind` stage */
        {
          $match: { "survey_user.user_option.option_id": "O12" }
        },
        /** After match you'll only have objects which met the criteria in `survey_user` array */
        /** group on `_id` & push entire original doc to data field */
        {
          $group: { _id: "$_id", survey_user: { $push: "$survey_user" }, data: {  $first: "$$ROOT" } }
        },
        /** Add `survey_user` array to `data.survey_user` & it's size to `data.optedCount` field */
        {
          $addFields: { "data.survey_user": "$survey_user", "data.optedCount": {  $size: "$survey_user" } }
        },
        /** Make `data` as new root to doc */
        {
          $replaceRoot: { newRoot: "$data" }
        }
      ])
    

    测试: mongoplayground

    以防万一您只需要计数但不需要返回整个文档,则上述查询将发生细微变化:

    类型 1 - 查询 2:

    db.collection.aggregate([
        {
          $match: { "survey_user.user_option.option_id": "O12" }
        },
        {
          $unwind: "$survey_user"
        },
        {
          $match: { "survey_user.user_option.option_id": "O12" }
        },
        /** Just group on `_id` & count no.of docs, maintain `survey_id` */
        {
          $group: { _id: "$_id", optedCount: { $sum: 1 }, survey_id: { $first: "$survey_id" } }
        }
      ])
    

    测试: mongoplayground

    使用数组迭代器$reduce,如果您的集合数据如此庞大,这可能会有所帮助,因为展开会爆炸您的文档。

    类型 2 - 查询:

    db.collection.aggregate([
      {
        $match: {
          "survey_user.user_option.option_id": "O12",
        },
      },
      /** Instead of `$addFields`, you can use `$project` to project fewer needed fields (which can be help improve query with performance benefits ) */
      {
        $addFields: {
          optedCount: {
            $reduce: {
              input: "$survey_user",
              initialValue: 0,
              in: {
                $cond: [
                  { $in: ["O12", "$$this.user_option.option_id"] },
                  { $add: ["$$value", 1] },
                  "$$value",
                ]
              }
            }
          }
        }
      }
    ]);
    

    测试: mongoplayground

    【讨论】:

      猜你喜欢
      • 2011-03-11
      • 1970-01-01
      • 2020-04-11
      • 2015-06-21
      • 1970-01-01
      • 2020-01-24
      • 2020-04-23
      • 1970-01-01
      • 2017-04-18
      相关资源
      最近更新 更多