【问题标题】:MongoDB Aggregation filter on documents within documentsMongoDB聚合过滤器对文档中的文档
【发布时间】:2022-01-27 14:53:26
【问题描述】:

你能帮我解决一个问题吗... 我有这个 json,但我想只返回节点。

{
   "_id":{
      "userArea":NumberInt(4927)
   },
   "pages":{
      "12":{
         "page":NumberInt(2635), 
         "progress":"COMPLETED",
         "progressType":"USER_PROGRESS",
         "end":11
      },
      "13":{
         "page":NumberInt(2627),
         "progress":"COMPLETED",
         "progressType":"USER_PROGRESS",
         "end":ISODate("2018-04-19T15:04:29.000+0000")
      }
      "14":{
         "page":NumberInt(2627),
         "progress":"CANCELLED",
         "progressType":"USER_PROGRESS",
         "end":ISODate("2018-04-19T15:04:29.000+0000")
      }
   }
}

这样......没有标题

      "12":{
         "page":NumberInt(2635), 
         "progress":"COMPLETED",
         "progressType":"USER_PROGRESS",
         "end":11
      },
      "13":{
         "page":NumberInt(2627),
         "progress":"COMPLETED",
         "progressType":"USER_PROGRESS",
         "end":ISODate("2018-04-19T15:04:29.000+0000")
      }

你能帮帮我吗?我只需要过滤完成的!!!

【问题讨论】:

    标签: mongodb filter mongodb-query aggregation-framework projection


    【解决方案1】:

    您可以使用此聚合查询:

    • 首先使用$objectToArray 生成一个数组,并可以使用值v 过滤值。这是在input 中完成的。
    • 然后使用该输入值,您可以过滤progress 值不是CANCELLED 的元素。并使用$arrayToObject 再次转换为对象
    db.collection.aggregate([
      {
        "$project": {
          "pages": {
            "$arrayToObject": {
              "$filter": {
                "input": {
                  "$objectToArray": "$pages"
                },
                "cond": {
                  "$ne": [
                    "$$this.v.progress",
                    "CANCELLED"
                  ]
                }
              }
            }
          }
        }
      }
    ])
    

    例如here

    抱歉,在我第一次尝试时,我读到了“无标题”,我以为你想使用 $replaceRoot,但我认为这个新查询是你想要的(也避免使用 $unwind)。

    但我认为您说“没有 hedaer”是为了显示问题中简化的输出。此外,如果您无法输出标题,只需使用$replaceRoot 添加一个新阶段。示例here

    【讨论】:

    • 但是我可以删除谁取消节点?
    • 我误解了这个问题,我已经编辑了。
    • 完美的 J.F. 第二个对我来说是完美的!非常感谢我的朋友!!!
    • 不错的一个。谢谢
    • 一般设计说明:一般来说,将值作为键是一个糟糕的主意,例如"12": { "page"... $objectToArray 技巧将键 (LVAL) 转换为值 (RVAL),但除非您绝对必须这样做,否则最好将您的数据建模为真实数组,例如"pages":[ { "pageID":"12", "page":NumberInt(2635), "progress":"COMPLETED", "progressType":"USER_PROGRESS", "end":11 }, { "pageID":"13", "page":NumberInt(2627), "progress":"COMPLETED", ... ]
    【解决方案2】:

    你需要像here那样做很多管道

    db.collection.aggregate([
      {
        "$project": {
          "p": {
            "$objectToArray": "$pages"
          }
        }
      },
      {
        "$unwind": "$p"
      },
      {
        "$match": {
          "p.v.progress": "COMPLETED"
        }
      },
      {
        "$group": {
          "_id": "$_id",
          "p": {
            "$addToSet": "$p"
          }
        }
      },
      {
        $project: {
          "a": {
            "$arrayToObject": "$p"
          }
        }
      },
      {
        "$replaceRoot": {
          "newRoot": "$a"
        }
      }
    ])
    
    1. 重塑形状,以便您可以应用过滤器。
    2. 再次分组以恢复原始架构。否则,您可以在 $match 管道处停止。

    如果可能,请更改您的架构,不要使用动态键。

    【讨论】:

    • 完美的吉布斯...谢谢!!!
    • 其他答案明显更小,不会产生$unwind 和$group 费用。
    • 是的,你的做法是对的。
    猜你喜欢
    • 2013-06-08
    • 2016-12-19
    • 2019-10-20
    • 2020-07-26
    • 1970-01-01
    • 2016-08-29
    • 1970-01-01
    • 2020-10-16
    • 2017-03-18
    相关资源
    最近更新 更多