Mongodb 重命名数组中的子文档字段

Mongodb 重命名数组中的子文档字段,mongodb,mongoose,mongodb-query,Mongodb,Mongoose,Mongodb Query,考虑到下面的文档,我如何将'techId1'重命名为'techId'。我尝试过不同的方法,但都没能成功 { "_id" : ObjectId("55840f49e0b"), "__v" : 0, "accessCard" : "123456789", "checkouts" : [ { "user" : ObjectId("5571e7619f"),

考虑到下面的文档,我如何将'techId1'重命名为'techId'。我尝试过不同的方法,但都没能成功

{
        "_id" : ObjectId("55840f49e0b"),
        "__v" : 0,
        "accessCard" : "123456789",
        "checkouts" : [ 
            {
                "user" : ObjectId("5571e7619f"),
                "_id" : ObjectId("55840f49e0bf"),
                "date" : ISODate("2015-06-19T12:45:52.339Z"),
                "techId1" : ObjectId("553d9cbcaf")
            }, 
            {
                "user" : ObjectId("5571e7619f15"),
                "_id" : ObjectId("55880e8ee0bf"),
                "date" : ISODate("2015-06-22T13:01:51.672Z"),
                "techId1" : ObjectId("55b7db39989")
            }
        ],
        "created" : ISODate("2015-06-19T12:47:05.422Z"),
        "date" : ISODate("2015-06-19T12:45:52.339Z"),
        "location" : ObjectId("55743c8ddbda"),
        "model" : "model1",
        "order" : ObjectId("55840f49e0bf"),
        "rid" : "987654321",
        "serialNumber" : "AHSJSHSKSK",
        "user" : ObjectId("5571e7619f1"),
        "techId" : ObjectId("55b7db399")
    }
在mongo控制台中,我尝试了使用它,但实际上没有任何更新

collection.update({"checkouts._id":ObjectId("55840f49e0b")},{ $rename: { "techId1": "techId" } });
我也试过了,这给了我一个错误。“无法使用部分(checkout.techId1的checkout)遍历元素”

在猫鼬中,我尝试了以下方法

collection.findByIdAndUpdate(id, { $rename: { "checkouts.techId1": "checkouts.techId" } }, function (err, data) {});


提前谢谢。

最后你很接近了,但是还缺少一些东西。使用“位置”操作符时不能使用,而是需要使用新名称和旧名称。但这里还有另一个限制,因为它们都属于作为父路径的“签出”,不能同时执行这两个操作

您问题中的另一个核心行是“遍历元素”,这是在一次更新“所有”数组元素时不能做的一件事。嗯,这并不安全,而且无论如何都可能会覆盖传入的新数据

您需要做的是“迭代”每个文档,并类似地迭代每个数组成员,以便“安全”地更新。您不能仅迭代文档,并通过修改“保存”整个数组。当然,在其他任何活动都在使用数据的情况下,情况并非如此

如果可以的话,我个人会在MongoDB shell中运行这种操作,因为这是一种“一次性”(希望如此)的操作,这样可以节省编写其他API代码的开销。我们也在使用here来尽可能提高效率。使用猫鼬需要更多的挖掘来实现,但仍然可以完成。但以下是shell列表:

var bulk=db.collection.initializeOrderedBulkOp(),
计数=0;
find({“checkout.techId1”:{“$exists”:true}}).forEach(函数(doc){
文档签出forEach(功能(签出){
if(checkout.hasOwnProperty(“techId1”){
bulk.find({“\u-id”:doc.\u-id,“checkout.\u-id”:checkout.\u-id}).updateOne({
“$set”:{“checkout.$.techId”:checkout.techId1}
});
bulk.find({“\u-id”:doc.\u-id,“checkout.\u-id”:checkout.\u-id}).updateOne({
“$unset”:{”签出。$.techId1”:1}
});
计数+=2;
如果(计数%500==0){
bulk.execute();
bulk=db.collection.initializeOrderedBulkOp();
}
}
});
});
如果(计数%500!==0)
bulk.execute();
由于
$set
$unset
操作是成对进行的,因此我们将每次执行的批处理总大小保持为1000个操作,以降低客户端的内存使用率

循环只是查找要重命名的字段“存在”的文档,然后迭代每个文档的每个数组元素并提交两个更改。作为批量操作,在调用
.execute()
之前,这些操作不会发送到服务器,并且每次调用都会返回一个响应。这节省了大量的交通

如果你坚持用猫鼬编码。请注意,从核心驱动程序获取批量API方法需要一个
.collection
acessor,如下所示:

var bulk=Model.collection.initializeOrderedBulkop();
唯一发送到服务器的是
.execute()
方法,因此这是您唯一的执行回调:

bulk.exectute(函数(错误、响应){
//这里的代码体和异步迭代器回调
});
并使用异步流控制而不是
.forEach()
,例如

另外,如果您这样做,那么请注意,作为一个不受mongoose控制的原始驱动程序方法,您不会获得与mongoose方法相同的数据库连接感知。除非您确定数据库连接已建立,否则最好将此代码放入服务器连接的事件回调中:

mongoose.connection.on(“connect”,函数(err){
//代码体
});

但除此之外,这些是您真正需要的唯一真正的(除了调用语法)更改。

这对我来说很有效,我创建了这个查询来执行这个过程,并与大家分享(尽管我知道这不是最优化的方式):

首先,使用
techId1
作为每个子文档的键之一,对具有
checkout
数组字段的文档进行排序。(2)
checkout
字段(从输入文档解构数组字段以输出每个元素的文档),(3)添加
techId
字段(带),(4)旧的
techId1
字段,(5)按
\u id
编辑文档,使
签出
子文档再次按其
\u id
进行分组,并(6)将这些聚合的结果写入
临时
集合(使用)

然后,您可以使用修改后的
签出
字段将此
临时
集合中的文档聚合到原始集合中

db.temporal.aggregate([
    {
        $merge: {
            into: collection,
            on: "_id",
            whenMatched:"merge",
            whenNotMatched: "insert"
        }
    }
])

这正是我想要的。非常感谢您的详细解释,在阅读您的答案后,请务必理解此概念。@fpena06我注意到我遗漏的一件事是添加了一个检查,以确保“techId1”元素确实存在于正在处理的数组元素上。假设它总是在那里可能没问题,但以防万一,我在包装数组迭代块的代码中添加了条件检查。
collection.update({'checkouts._id': n1._id}, { $rename: { "checkouts.$.techId1": "checkouts.$.techId" } }, function (err, data) {});
const collection = 'yourCollection'

db[collection].aggregate([
    {
        $match: {
            'checkouts.techId1': { '$exists': true }
        }
    },
    {
        $unwind: {
            path: '$checkouts'
        }
    },
    {
        $addFields: {
            'checkouts.techId': '$checkouts.techId1'
        }
    },
    {
        $project: {
            'checkouts.techId1': 0
        }
    },
    {
        $group: {
            '_id': '$_id',
            'checkouts': { $push: { 'techId': '$checkouts.techId' } }
        }
    },
    {
        $out: 'temporal'
    }
])
db.temporal.aggregate([
    {
        $merge: {
            into: collection,
            on: "_id",
            whenMatched:"merge",
            whenNotMatched: "insert"
        }
    }
])