我有一个包含此表单文档的集合:
{
"name" : "John Smith",
"store_affiliation" : {
"stores" : {
"ABCD" : {
"role" : "General Manager",
"startdate" : ISODate("1970-01-01T00:00:00.000+0000"),
"enddate" : ISODate("1980-01-01T00:00:00.000+0000"),
"permissions" : "GM"
},
"1234" : {
"role" : "Owner",
"startdate" : ISODate("1970-01-01T00:00:00.000+0000"),
"enddate" : null,
"permissions" : "ALL"
},
"4321" : {
"role" : "Owner",
"startdate" : ISODate("1990-01-01T00:00:00.000+0000"),
"enddate" : null,
"permissions" : "ALL"
}
}
}
...但我需要以这种形式存储的商店列表(“商店”数组):
{ "name" : "John Smith",
"store_affiliation" : {
"stores" : [
{
"store_code" : "ABCD",
"role" : "General Manager",
"startdate" : ISODate("1970-01-01T00:00:00.000+0000"),
"enddate" : ISODate("1980-01-01T00:00:00.000+0000"),
"permissions" : "GM"
},
{
"store_code" : "1234",
"role" : "Owner",
"startdate" : ISODate("1970-01-01T00:00:00.000+0000"),
"enddate" : null,
"permissions" : "ALL"
},
{
"shop_id" : "4321",
"role" : "Owner",
"startdate" : ISODate("1990-01-01T00:00:00.000+0000"),
"enddate" : null,
"permissions" : "ALL"
}
]
}
我已经在$project
管道中使用$group
,$push
和aggregate
进行了研究,但我觉得使用aggregate
甚至可能是死路一条,因为我不是在查询结果之后;我正在尝试永久修改集合中的每个文档(数千个)。
答案 0 :(得分:3)
您可以在3.4
版本中尝试以下聚合管道。
下面的聚合将stores
嵌入文档更改为键值对数组,使用$objectToArray
后跟$map
输出带有新字段的转换数组,同时保留所有现有字段。
批量更新以编写新商店结构。
var bulk = db.getCollection(col).initializeUnorderedBulkOp();
var count = 0;
var batch = 1;
db.getCollection(col).aggregate([
{"$match":{"store_affiliation.stores":{"$ne":{"$type":4}}}},
{"$addFields":{
"stores":{
"$map":{
"input":{"$objectToArray": "$store_affiliation.stores"},
"in":{
"store_code":"$$this.k",
"role":"$$this.v.role",
"startdate":"$$this.v.startdate",
"enddate":"$$this.v.enddate",
"permissions":"$$this.v.permissions"
}
}
}
}}]).forEach(function(doc){
var _id = doc._id;
var stores = doc.stores;
bulk.find({ "_id" : _id }).updateOne(
{ $set: {"store_affiliation.stores" : stores} }
);
count++;
if (count == batch) {
bulk.execute();
bulk = db.getCollection(col).initializeUnorderedBulkOp();
count = 0;
}
});
if (count > 0) {
bulk.execute();
}