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



如果我想使用Scala删除MongoDB集合中的重复文档,该怎么做?

很确定这很简单,但我总是一直在 Mongo Shell 中寻找做到这一点的方法。

使用 MongoDB Scala 驱动程序

在此示例中,我将 2.1.0 版本用于 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")
)
}

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

现在是棘手的部分。我将逐行解释它。首先,我们将每个文档映射到一个元组,其中第一个元素是没有_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))

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

.filter(_.size > 1)

Le's 取每个序列的前 n-1 _ids。它们将是要删除的重复文档。

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

让我们展平序列,以便我们有一个_ids序列。

.flatten

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

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

希望对您有所帮助!

最新更新