У вас есть несколько вариантов в зависимости от версии MongoDB:
Для выпусков 3.4.4 и выше используйте $objectToArray
и динамически выбирайте поля:
db.collection.aggregate([
{ "$addFields": {
"address": {
"$let": {
"vars": {
"address": {
"$reduce": {
"input": { "$objectToArray": "$address" },
"initialValue": "",
"in": { "$concat": [ "$$value", "$$this.v", ", " ] }
}
}
},
"in": {
"$concat": [ "#",
{ "$substrCP": [
"$$address",
0,
{ "$subtract": [{ "$strLenCP": "$$address" }, 2] }
]}
]
}
}
}
}},
{ "$out": "newcollection" }
])
Для версии 3.4 перед второстепенным выпуском используйте $filter
для удаления значений null
db.collection.aggregate([
{ "$addFields": {
"address": {
"$let": {
"vars": {
"address": {
"$reduce": {
"input": {
"$filter": {
"input": [
"$address.flatNo", "$address.street", "$address.city",
"$address.zip","$address.state","$address.country"
],
"cond": { "$ne": [ "$$this", null ] }
}
},
"initialValue": "",
"in": { "$concat": [ "$$value", "$$this", ", " ] }
}
}
},
"in": {
"$concat": [ "#",
{ "$substrCP": [
"$$address",
0,
{ "$subtract": [{ "$strLenCP": "$$address" }, 2] }
]}
]
}
}
}
}},
{ "$out": "newcollection" }
])
До версии 3.4 у вас нет $reduce
или $strLenCP
, что обеспечивает динамическое "соединение". Так что вы, вероятно, хотите сделать это в коде:
var batch = [];
db.collection.find({}, { _id: 0, address: 1 }).forEach(doc => {
doc.address = "#" + Object.keys(doc.address).map(k => doc.address[k]).join( ", ");
batch.push(doc);
if ( batch.length >= 1000 ) {
db.newcollection.insertMany(batch);
batch = [];
}
})
if ( batch.length > 0 ) {
db.newcollection.insertMany(batch);
batch = [];
}
Или действительно долго сматывается с $ifNull
и $cond
:
db.collection.aggregate([
{ "$project": {
"address": {
"$concat": [
"#",
{ "$ifNull": [ "$address.flatNo", ""] },
{ "$cond": [{ "$ifNull": [ "$address.flatNo", false ] }, ", ", ""] },
{ "$ifNull": [ "$address.street", "" ] },
{ "$cond": [{ "$ifNull": [ "$address.street", false ] }, ", ", ""] },
{ "$ifNull": [ "$address.city", "" ] },
{ "$cond": [{ "$ifNull": [ "$address.city", false ] }, ", ", ""] },
{ "$ifNull": [ "$address.zip", "" ] },
{ "$cond": [{ "$ifNull": [ "$address.zip", false ] }, ", ", ""] },
{ "$ifNull": [ "$address.state", "" ] },
{ "$cond": [{ "$ifNull": [ "$address.state", false ] }, ", ", ""] },
{ "$ifNull": [ "$address.country", "" ] }
]
}
}}
])
Кодовый подход будет более понятным, но если вы пишете в другую коллекцию, то $ifNull
с $cond
по крайней мере позволяет использовать $out
, чтобы избежать пересылки всех документов «по проводам» перед повторной записью.