【问题标题】:Mongo remove duplicates in array of objects based on fieldMongo根据字段删除对象数组中的重复项
【发布时间】:2020-04-01 00:30:07
【问题描述】:

Mongo 的新手,发现了很多使用聚合框架从字符串数组中删除欺骗的示例,但我想知道是否可以根据对象中的字段从对象数组中删除欺骗。例如

{
"_id" : ObjectId("5e82661d164941779c2380ca"),
"name" : "something",
"values" : [
    {
        "id" : 1,
        "val" : "x"
    },
    {
        "id" : 1,
        "val" : "x"
    },
    {
        "id" : 2,
        "val" : "y"
    },
    {
        "id" : 1,
        "val" : "xxxxxx"
    }
]
}

在这里,我想根据id 字段删除欺骗。所以最终会得到 ​​p>

{
"_id" : ObjectId("5e82661d164941779c2380ca"),
"name" : "something",
"values" : [
    {
        "id" : 1,
        "val" : "x"
    },
    {
        "id" : 2,
        "val" : "y"
    }
]
}

选择具有给定 id 的第一个/任何对象都有效。只想以每个 id 结束。这在聚合框架中可行吗?甚至在聚合框架之外,只是寻找一种干净的方法来做到这一点。需要在集合中的许多文档中执行此类操作,这似乎是聚合框架的一个很好的用例,但正如我所提到的,这里的新手......谢谢。

【问题讨论】:

    标签: mongodb aggregation-framework


    【解决方案1】:

    嗯,你可以通过两种方式得到想要的结果。

    经典

    展平 - 删除重复项(选择第一次出现) - 分组方式

    db.collection.aggregate([
      {
        $unwind: "$values"
      },
      {
        $group: {
          _id: "$values.id",
          values: {
            $first: "$values"
          },
          id: {
            $first: "$_id"
          },
          name: {
            $first: "$name"
          }
        }
      },
      {
        $group: {
          _id: "$id",
          name: {
            $first: "$name"
          },
          values: {
            $push: "$values"
          }
        }
      }
    ])
    

    MongoPlayground

    现代

    我们需要使用$reduce 运算符。

    伪代码:

    values : {
      var tmp = [];
      for (var value in values) {
          if !(value.id in tmp)
            tmp.push(value);
      }
      return tmp;
    }
    

    db.collection.aggregate([
      {
        $addFields: {
          values: {
            $reduce: {
              input: "$values",
              initialValue: [],
              in: {
                $concatArrays: [
                  "$$value",
                  {
                    $cond: [
                      {
                        $in: [
                          "$$this.id",
                          "$$value.id"
                        ]
                      },
                      [],
                      [
                        "$$this"
                      ]
                    ]
                  }
                ]
              }
            }
          }
        }
      }
    ])
    

    MongoPlayground

    【讨论】:

    • 谢谢! “经典”和“现代”在性能或处理大型收藏方面有什么区别/偏好吗?
    • @chacmool 需要试试。如果您想查看基准,请告诉我。
    • 爱只有反应
    • 我得到错误 undefined variable for "value" 我们在哪里定义值?
    • @JayHaran $$value$$this$reduce 运算符的保留变量。如果你迭代一个数组,$$this 是迭代项,而$$value 是最后存储的项
    【解决方案2】:

    你可以使用$reduce,试试下面的查询:

    db.collection.aggregate([
      {
        $addFields: {
          values: {
            $reduce: {
              input: "$values",
              initialValue: [],
              in: {
                $cond: [
                  { $in: ["$$this.id", "$$value.id"] }, /** Check if 'id' exists in holding array if yes push same array or concat holding array with & array of new object */
                  "$$value",
                  { $concatArrays: ["$$value", ["$$this"]] }
                ]
              }
            }
          }
        }
      }
    ]);
    

    测试: MongoDB-Playground

    【讨论】:

    • 正在输入解释:D
    • @Valijon :没听懂你在说什么?
    • 我发布了相同的解决方案并正在编写解释。但是你先发帖了
    • @Valijon :-) :-)
    猜你喜欢
    • 2021-06-03
    • 2012-05-17
    • 2020-06-29
    • 2015-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多