【问题标题】:Mongodb - delete docs from collection that do not have unique valueMongodb - 从集合中删除没有唯一值的文档
【发布时间】:2017-03-15 01:08:41
【问题描述】:

我有这样的对象集合:

{"_id":"...", "user":"foo", "value":"a"}, // this one stays coz its user is foo
{"_id":"...", "user":"bar", "value":"a"}, // remove this one
{"_id":"...", "user":"baz", "value":"a"}, // remove this one
{"_id":"...", "user":"qux", "value":"b"}, // this one has unique value so it doesn't get deleted

我想查找并删除所有具有重复值的对象,除非用户是foo

有 JS mongoshell 方法吗?

【问题讨论】:

    标签: javascript mongodb mongo-shell


    【解决方案1】:

    这是我对在 mongoDB 中获取重复项的看法。 aggregate 是一个有用的功能。您可以应用多个管道来到达您想要的位置。 aggregate

    1. 匹配所有不等于 foo 的用户
    2. 将它们按value 分组,这将是_id 并增加文档集中找到的每个$_id(原始)的计数。将项目推送到名为 docIds 的数组中。
    3. 从这个新集合中获取 $count > 1 的所有行/文档
    4. 放松(请查看文档以获得更好的解释)

    这将为您提供多次出现value 的文档。一旦您对结果集感到满意,您就可以对这些文档执行删除操作。我还没有手动运行这个...让我们知道..

    db.collection.aggregate([{
                $match: {
                    "user": {
                        $ne: "foo"
                    }
                }
            }, {
                $group: {
                    _id: "$value",
                    docIds: {
                        $push: "$_id"
                    },
                    count: {
                        $sum: 1
                    }
                }
            }, {
                $match: "$count": {
                    $gt: 1
                }
            }, {
                $unwind: $docIds
            }
        ])
    

    【讨论】:

      【解决方案2】:

      好的,这还没有经过测试,但你去吧...这是假设使用 Mongoose 与数据库交互...

      let values = [];
      let deleteIds = [];
      
      myModel.find({}).then(docs => {
          docs.forEach(d => {
              if (values.indexOf(d.value)) {
                  deleteIds.push(d._id);
              } else {
                  values.push(d.value);
              }
          })
      
          deleteIds.forEach(id => {
              myModel.findOneAndRemove({_id: id});
          });
      });
      

      【讨论】:

      • 这段代码是否适用于 300 万条记录?除此之外,我认为 mongo shell 解决方案更适合我的情况
      • 是的,但您希望多久执行一次此操作?
      • 我只需要清理我的数据库一次。
      【解决方案3】:

      我通过使用这个代码块解决了这个问题(这不是这个功能的完整代码):

      let query = {
        user:targetedUser
      }
      let projection = {
        _id:0, id:1, user:1
      }
      
      
      collection.find(query, projection)
            .on('data', doc => {
              collection.deleteMany({id:doc.id, user: {$not: new RegExp(targetedUser)}})
            })
            .on('end', _=> {
              db.close()
            })
      

      基本上targetedUser 变量是您想要保留的对象的值,同时删除所有其他重复且不匹配该值的对象。查看它,从其他用户中删除所有重复项,同时为特定用户保留它们。

      这是非常特殊的情况,对于常见问题可能会有所不同。但是这个答案的重点是,这段代码可能看起来会吃掉所有的 RAM,但与我迄今为止尝试过的其他实现相比,300 万条记录占用的空间不超过 20MB,而且速度也很快.

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-02-21
        • 1970-01-01
        • 1970-01-01
        • 2020-11-11
        • 1970-01-01
        • 2013-08-23
        • 1970-01-01
        相关资源
        最近更新 更多