如何使用批量 read/write 将每个文档的一部分转换为每个文档中的数组?
How to transform part of each document into an array in each document using bulk read/write?
我有这样的文件
{
"field1" : "value",
"field3" : "value",
"attributes" : {
"key1" : {
"category" : "4",
"value" : "value"
},
"key2" : {
"category" : "5",
"value" : "value"
},
}
}
我想将它们转换为如下所示的结构(基本上是使用字典并将其展平为数组)。请注意 attributes
中的键数会有所不同。
{
"field1" : "value",
"field3" : "value",
"attributes" : [
{
"key" : "key1",
"category" : "4",
"value" : "value"
},
{
"key" : "key2",
"category" : "5",
"value" : "value"
},
]
}
由于文档数量较多,我想使用批量API。我的脚本有这个基本结构。
db = db.getSiblingDB('MyDB');
db.MyCollection.intializeOrderedBukOp(),
var bulk = db.MyCollection.intializeOrderedBukOp(),
count = 0;
db.MyCollection.find({}).forEach(function(doc) {
// Re-map attrs (what follows is some pseudocode
var attrs = function TransformSomehow(doc.attributes) {
// return an array...
};
});
// Queue update operation
bulk.find({ "_id": doc._id })
.updateOne({
"$set": { "attrs": attrs } }
});
count++;
// Execute every 1000
if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.collection.intializeOrderedBukOp();
}
});
// Drain any queued remaining
if ( count % 1000 != 0 )
bulk.execute();
这是从 this answer 借来的,但我不能按原样使用它,因为它的方向相反(数组到对象)。看来我无法使用 map
来执行此操作。
这是使用 MongoDB NodeJS 驱动程序 v3.6 和 MongoDB v4.2.3 进行批量写入的一种方法。这使用一个简单的批处理来更新所有集合文档。更新将每个文档的对象(或字典)转换为数组(根据您的要求)。
const collection = db.collection('test');
const update1 = {
updateMany: {
filter: { },
update: [
{ $set: {
attributes: {
$map: {
input: { $objectToArray: "$attributes" },
in: { $mergeObjects: [ { "key": "$$this.k" }, "$$this.v" ] }
}
}
} }
]
}
};
collection.bulkWrite( [ update1 ],
{ ordered: false },
( err, result ) => {
console.log( 'Updated and modified count: ', result.matchedCount, result.modifiedCount );
}
)
@prasad_ 的回答有效。对于那些想在没有 NodeJS 的 MongoDB 控制台中应用它的人,我将他的解决方案翻译成这个。
col = db.getCollection('X');
update1 = {
updateMany: {
filter: { },
update: [
{ $set: {
attributes: {
$map: {
input: { $objectToArray: "$attributes" },
in: { $mergeObjects: [ { "key": "$$this.k" }, "$$this.v" ] }
}
}
} }
]
}
}
col.bulkWrite( [ update1 ], { ordered: false })
我有这样的文件
{
"field1" : "value",
"field3" : "value",
"attributes" : {
"key1" : {
"category" : "4",
"value" : "value"
},
"key2" : {
"category" : "5",
"value" : "value"
},
}
}
我想将它们转换为如下所示的结构(基本上是使用字典并将其展平为数组)。请注意 attributes
中的键数会有所不同。
{
"field1" : "value",
"field3" : "value",
"attributes" : [
{
"key" : "key1",
"category" : "4",
"value" : "value"
},
{
"key" : "key2",
"category" : "5",
"value" : "value"
},
]
}
由于文档数量较多,我想使用批量API。我的脚本有这个基本结构。
db = db.getSiblingDB('MyDB');
db.MyCollection.intializeOrderedBukOp(),
var bulk = db.MyCollection.intializeOrderedBukOp(),
count = 0;
db.MyCollection.find({}).forEach(function(doc) {
// Re-map attrs (what follows is some pseudocode
var attrs = function TransformSomehow(doc.attributes) {
// return an array...
};
});
// Queue update operation
bulk.find({ "_id": doc._id })
.updateOne({
"$set": { "attrs": attrs } }
});
count++;
// Execute every 1000
if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.collection.intializeOrderedBukOp();
}
});
// Drain any queued remaining
if ( count % 1000 != 0 )
bulk.execute();
这是从 this answer 借来的,但我不能按原样使用它,因为它的方向相反(数组到对象)。看来我无法使用 map
来执行此操作。
这是使用 MongoDB NodeJS 驱动程序 v3.6 和 MongoDB v4.2.3 进行批量写入的一种方法。这使用一个简单的批处理来更新所有集合文档。更新将每个文档的对象(或字典)转换为数组(根据您的要求)。
const collection = db.collection('test');
const update1 = {
updateMany: {
filter: { },
update: [
{ $set: {
attributes: {
$map: {
input: { $objectToArray: "$attributes" },
in: { $mergeObjects: [ { "key": "$$this.k" }, "$$this.v" ] }
}
}
} }
]
}
};
collection.bulkWrite( [ update1 ],
{ ordered: false },
( err, result ) => {
console.log( 'Updated and modified count: ', result.matchedCount, result.modifiedCount );
}
)
@prasad_ 的回答有效。对于那些想在没有 NodeJS 的 MongoDB 控制台中应用它的人,我将他的解决方案翻译成这个。
col = db.getCollection('X');
update1 = {
updateMany: {
filter: { },
update: [
{ $set: {
attributes: {
$map: {
input: { $objectToArray: "$attributes" },
in: { $mergeObjects: [ { "key": "$$this.k" }, "$$this.v" ] }
}
}
} }
]
}
}
col.bulkWrite( [ update1 ], { ordered: false })