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