【问题标题】:MongoDB find all the object that contains an array which has consecutive matching valueMongoDB查找包含具有连续匹配值的数组的所有对象
【发布时间】:2022-04-10 01:42:20
【问题描述】:

我有一个如下所示的 MongoDB 集合:

{
  _id: "some-long-id-1"
  name: "John Doe",
  activities: [
    { name: "Lunch", status: "SCHEDULED" },
    { name: "Playing Football", status: "COMPLETED" },
    { name: "Workout", status: "COMPLETED" },
  ]
},
{
  _id: "some-long-id-2"
  name: "Jane Doe",
  activities: [
    { name: "Lunch", status: "COMPLETED" },
    { name: "Playing Football", status: "SCHEDULED" },
    { name: "Workout", status: "COMPLETED" },
  ]
}

我想查询所有具有activities 的对象,其中至少包含一个连续的COMPLETED 状态。例如,查询应该返回some-long-id-1 对象,因为它在活动数组中具有连续的COMPLETED 状态。它不应该返回some-long-id-2,因为即使有两个数组具有COMPLETED 状态但它们不是连续的。

【问题讨论】:

    标签: mongodb mongodb-query


    【解决方案1】:

    您可以使用 $reduce 来执行此操作。如果找到连续的“COMPLETED”,则使用标志consecutiveFound 的元组来存储;和lastStatus 存储最后一个元素的状态。

    累加器的初始值可以是这样的:

    {
        "consecutiveFound": false,
        "lastStatus": ""
    }
    

    对于$reduce的逻辑,如果consecutiveFoundtrue,我们发现已经连续,所以保持"consecutiveFound": true。 如果"consecutiveFound": false,我们只是不断比较lastStatus和当前状态,看看它们是否都完成了。只有当我们发现两者都是COMPLETED 时,我们才将累加器值更新为"consecutiveFound": true。记得每次都将累加器中的当前值更新为lastStatus

    {
        "$reduce": {
            "input": "$activities",
            "initialValue": {
            "consecutiveFound": false,
            lastStatus: ""
            },
            "in": {
            "$cond": {
                "if": {
                $or: [
                    {
                    $eq: [
                        "$$value.consecutiveFound",
                        true
                    ]
                    },
                    {
                    $and: [
                        {
                        $eq: [
                            "$$value.lastStatus",
                            "COMPLETED"
                        ]
                        },
                        {
                        $eq: [
                            "$$this.status",
                            "COMPLETED"
                        ]
                        }
                    ]
                    }
                ]
                },
                "then": {
                    "consecutiveFound": true,
                    lastStatus: "$$this.status"
                },
                "else": {
                    "consecutiveFound": false,
                    lastStatus: "$$this.status"
                }
            }
            }
        }
    }
    

    这是Mongo playground 供您参考。

    【讨论】:

      【解决方案2】:

      查询

      • 将数组减少为一个数字(计算我们找到的连续数)
        • 0 未找到
        • 1 找到一个
        • 找到 2 个 2
      • 我们需要 reduce 结果为 = 2
      • 如果 2 => 保留 2
        else if "completed" => inc 数字
        else 0(重新开始计数)

      PlayMongo

      aggregate(
      [{"$match": 
          {"$expr": 
            {"$eq": 
              [{"$reduce": 
                  {"input": "$activities",
                    "initialValue": 0,
                    "in": 
                    {"$switch": 
                      {"branches": 
                        [{"case": {"$eq": ["$$value", 2]}, "then": "$$value"},
                          {"case": {"$eq": ["$$this.status", "COMPLETED"]},
                            "then": {"$add": ["$$value", 1]}}],
                        "default": 0}}}}, 2]}}}])
      

      【讨论】:

        猜你喜欢
        • 2015-04-28
        • 2016-10-18
        • 1970-01-01
        • 2020-02-11
        • 2019-11-14
        • 1970-01-01
        • 2023-02-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多