使用 $addFields 将 _id 设置为新的 UUID

Set _id to a new UUID using $addFields

好吧,有人搞砸了。不是我,但我要解决它。我需要做的是用新的 UUID 替换集合中每个文档的 _id

我的计划是聚合整个集合,使用 $addFields 替换 _id,然后将其合并回自身,替换记录。幸运的是,有一个辅助(复合)键可用于合并,所以我很擅长 — 我想,因为我还没有做到。

我面临的问题是在 $addFields 阶段生成一个唯一的(这有点重要)UUID。

db.foo.agregate([
    {
        $addFields: {
            // I really just need the UUID string itself, hence the split
            '_id': UUID().toString().split('"')[1]
        }
    }
    // here's where the merge would go
])

这里的问题是 UUID() 只被调用了一次,所以我得到了所有相同的 ID。这不是我想要的。

现在乏味的方法是从一个循环中一个一个地做这件事。但是有没有一种方法可以在聚合管道中一次完成此操作?


现在我发现 问了基本相同的问题,但它是通过不使用 UUID 而是使用顺序键解决的,所以它确实不是我问题的答案.

如果你需要做的是

What I need to do, is replace the _id of each and every document in the collection with a new UUID.

...并且您可以使用 ObjectId 而不是 UUID,那么:

  • 投影出 _id
  • $out 进入新的 collection

服务器应在插入期间为每个文档生成新的 _id。

然后:

  • 放弃原来的collection
  • 将新的collection重命名为原来的名字

所以这个答案只是通过从 $function 调用 UUID() 来生成唯一的 UUIDs。试试这个:

db.collectionName.aggregate([
    {
        $addFields: {
            _id: {
                $function: {
                    body: function() {
                        return UUID().toString().split('"')[1];
                    },
                    args: [],
                    lang: "js"
                }
            }
        }
    }
])

顺便说一句,它只适用于 MongoDB 版本 >= 4.4。 输出:

/* 1 */
{
    "_id" : "5dc9316a-50a8-4013-8090-06fc66cdce9f",
    "dummy" : "data"
},

/* 2 */
{
    "_id" : "062ebc8f-4455-4a81-a9e0-34f6c7132cab",
    "dummy" : "data"
},

/* 3 */
{
    "_id" : "94eef4b8-9c0e-4910-a1cb-58443a63a036",
    "dummy" : "data"
}