MongoDB Scala - 删除集合中的重复文档

问题描述 投票:-2回答:1

如果我想使用Scala删除MongoDB集合中的重复文档,那么如何去做呢?

很确定它很简单,但我总是在Mongo Shell中找到方法。

mongodb scala collections duplicates document
1个回答
0
投票

使用MongoDB Scala driver

在这个例子中,我使用版本2.1.0 for Scala 2.11。

我想您要删除除了_id字段之外重复相同属性的所有文档。

我在用户集合中有四个文档。

{
  "_id": <ObjectId>,
  "name": "John",
  "surname": "Doe"
}
{
  "_id": <ObjectId>,
  "name": "John",
  "surname": "Doe"
}
{
  "_id": <ObjectId>,
  "name": "John",
  "surname": "Doe"
}
{
  "_id": <ObjectId>,
  "name": "Dione",
  "surname": "Elton"
}

在这个例子中,我们将删除name = John和surname = Doe的三个文档中的两个,保留这些文档:

{
  "_id": <ObjectId>,
  "name": "John",
  "surname": "Doe"
}
{
  "_id": <ObjectId>,
  "name": "Dione",
  "surname": "Elton"
}

我已经使用过此代码,它适用于此示例:

val client = MongoClient("mongodb://localhost:27017")
val database = client.getDatabase("test")
val collection = database.getCollection("users")

val future = collection.find().toFuture()
val allDocs = Await.result(future, Duration.Inf)

allDocs
  .map { d => (d.filterKeys { x => !x.equals("_id")}, d.get("_id").get ) }
  .groupBy(_._1)
  .map(_._2.map(_._2))
  .filter(_.size > 1)
  .map({ids => ids.take(ids.size - 1)})
  .flatten
  .foreach{
    id => collection.deleteOne(equal("_id", id)).subscribe(
      (dr: DeleteResult) => println(dr.getDeletedCount),
      (e: Throwable) => println(s"Error when deleting the document $id: $e")
    )
  }

三个第一行非常简单,我们连接到我们的数据库并获取集合对象。然后,我们从集合中检索所有文档。请注意,MongoDB Scala驱动程序是异步的,所以我采用了未来的对象以等待结果,因为我需要它们继续。

现在是棘手的部分。我将逐行解释。首先,我们将每个文档映射到一个元组,其中第一个元素是没有_id字段的文档,第二个元素是_id。

  .map { d => (d.filterKeys { x => !x.equals("_id")}, d.get("_id").get ) }

一旦我们有了元组,我们就可以按照没有_id字段的文档对序列进行分组。它将生成一个映射,其中键是没有_id字段的文档,值是元组序列,它们表示每个对(没有_id,_id的文档),其内容与键相同。

  .groupBy(_._1)

由于我们对_ids感兴趣,我们需要获取每个Map对象的值,并且对于值序列的每个元素,都需要_id。

  .map(_._2.map(_._2))

现在我们有一系列序列。每个序列都包含没有_id的每个唯一文档的_ids。下一步是过滤序列,以便我们只有那些大小大于1的序列。换句话说,我们正在过滤表示重复文档的_ids。

  .filter(_.size > 1)

Le取每个序列的n-1个第一个_id。它们将是要删除的重复文档。

  .map({ids => ids.take(ids.size - 1)})

让我们展平序列的顺序,这样我们就有了一系列_ids。

  .flatten

最后,我们可以从我们的集合中删除每个_id。我是通过使用foreach方法完成的,并逐个删除文档。由于我们使用的是subscribe方法,因此将异步删除文档。

  .foreach{
    id => collection.deleteOne(equal("_id", id)).subscribe(
      (dr: DeleteResult) => println(dr.getDeletedCount),
      (e: Throwable) => println(s"Error when deleting the document $id: $e")
    )
  }

希望能帮助到你!

© www.soinside.com 2019 - 2024. All rights reserved.