Need some real help on this! And only you can help me!
Currently writing a MongoDb migration and I'm required to add some new fields to a nested object of unknown field name
Example of document:
{
"_id" : "1a3a5c0c-4542-4bcc-9965-5c04db8d3edc",
"name" : "Test_person",
"connections" : {
"540e1234-field_random_num" : {
"some_field_1" : "Garbage_string_1",
"some_field_2" : {
"sub_field_1" : 1234,
"sub_field_2" : 5678,
"sub_field_3" : null,
}
},
"48925678-field_random_num_2" : {
"some_field_1" : "Garbage_string_2",
"some_field_2" : {
"sub_field_1" : 4321,
"sub_field_2" : 8765,
"sub_field_3" : null,
}
}
}
}
Given this document, where connections: { [id: string]: some_object_type }
Note that :
some_object_type: {
some_field_1: string,
some_field_2: sub_object_type
}
and
sub_object_type: {
"sub_field_1" : number
"sub_field_1" : number
"sub_field_1" : string
}
Have tried using $[]
which has worked for other collections in the same migration script. Sadly, $
is not of much help, given that its usage is limited to arrays.
My current train of thought has led me to believe that the right approach lays in the evaluation query operator $where
, in order to isolate the randomly named id : string
object field
Long story short... looking for an alternative to the $[]
operator to use with objects
The updated document will look like this:
{
"_id" : "1a3a5c0c-4542-4bcc-9965-5c04db8d3edc",
"name" : "Test_person",
"connections" : {
"540e1234-field_random_num" : {
"some_field_1" : "Garbage_string_1,
"some_field_2" : {
"sub_field_1" : 1234,
"sub_field_2" : 5678,
"sub_field_3" : null,
"new_sub_field" : null <-- new field
}
},
"48925678-field_random_num_2" : {
"some_field_1" : "Garbage_string_2",
"some_field_2" : {
"sub_field_1" : 4321,
"sub_field_2" : 8765,
"sub_field_3" : null,
"new_sub_field" : null <-- new field
}
}
}
}
You can get desired result in 2 ways:
Shell JS: We can execute JS code with recursive function:
db.collection.find({}).forEach(function(doc){
function _(obj){
//Iterate
for(var key in obj){
//If key is some_field_2, we insert inside new key:value
if(key == "some_field_2"){
obj[key]["new_sub_field"] = null;
// If value is object, we call recursive function
} else if (typeof(obj[key]) == "object"){
obj[key] = _(obj[key]);
}
}
return obj;
}
print(_(doc))
})
Aggregation: With $objectToArray we normalize connection
into key:value
array.
We convert
{"connection": {"foo":"bar", "buz" : "foobar"}}
into
{"connection": [{"k":"foo", "v":"bar"}, {"k":"buz", "v":"foobar"}]}`
We go down till sub_object_type
field and add new new_sub_field
field with $mergeObjects
. To convert normalized array into object, we use $arrayToObject
db.collection.aggregate([
{
$project: {
_id: 1,
name: 1,
connections: {
$arrayToObject: {
$map: {
input: {
$objectToArray: "$connections"
},
as: "conn",
in: {
k: "$$conn.k",
v: {
$arrayToObject: {
$map: {
input: {
$objectToArray: "$$conn.v"
},
as: "some_field",
in: {
k: "$$some_field.k",
v: {
$cond: [
{
$eq: [
"$$some_field.k",
"some_field_2"
]
},
{
$mergeObjects: [
"$$some_field.v",
{
"new_sub_field": null
}
]
},
"$$some_field.v"
]
}
}
}
}
}
}
}
}
}
}
}
])
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.