update nested arrays from flat file - mongodb
Seems this question is a very popular one, but I haven't found an answer (or at least not one I was able to understand).
I'm having a flat file that I would like to store in Mongo using some nestings. Though it is relatively easy to achieve with an insert and unique content I have the need to update the content on a regular base, so would need to be able to use the update commands also.
My flat file looks as follows :
Model,Category,Organisation,CountryCode,CountryWarranty,PeriodCode,PeriodQty
Model1,Category1,Org1,Code1,2Y,201707,1
Model1,Category1,Org1,Code1,2Y,201708,2
Model1,Category1,Org1,Code1,1Y,201709,3
Model1,Category1,Org1,Code2,2Y,201707,7
Model1,Category1,Org1,Code2,2Y,201708,8
Model1,Category1,Org1,Code2,5Y,201709,7
Model1,Category1,Org2,Code3,2Y,201707,5
Model1,Category1,Org2,Code3,4Y,201708,6
Model1,Category1,Org2,Code3,2Y,201709,7
...
Model_n,Category_n,Org_n,Code_n,3Y,201802,20
and what I like to achieve is the following :
{
"_id": "Model1",
"Model_category": "Category1",
"Product_Sales": [
{
"Organisation": "Org1",
"Country": [
{
"Code": "Code1",
"Guarantee_Years": "2Y",
"Period": [
{"Code": 201707,"Qty": 1},
{"Code": 201708,"Qty": 2},
{"Code": 201709,"Qty": 3}
]
}, {
"Code": "Code2",
"Guarantee_Years": "2Y",
"Period": [
{"Code": 201707,"Qty": 7},
{"Code": 201708,"Qty": 8},
{"Code": 201709,"Qty": 7}
]
}
]
}, {
"Organisation": "Org2",
"Country": [
{
"Code": "Code3",
"Guarantee_Years": "2Y",
"Period": [
{"Code": 201707,"Qty": 5},
{"Code": 201708,"Qty": 6},
{"Code": 201709,"Qty": 7}
]
}
]
}
]
}
Below a snippet of what I tried, note that the syntax is specific to my development environment so I know it is not workable or proper mongo, but it's about the basic idea. Any example using the console will do fine for me
concat("{update: "master_Sales",
updates: [
{
q:{"_id":", %{_id},""},
u:{$addToSet: {
"Product_Sales.Organisation": "", %{org}, "",
"Product_Sales.Organisation.Country": [
-- more here but have no clue --
]
}}
, upsert: true}
]}"
)
Adding my organisations works fine, but as soon as I want to add a second level (nested within an org) it goes wrong.
So in essence I want to be able to add this flat content to my Mongo in a nested array structure, and each time one of the values is changed in the future (say the quantity is updated, or a new country is added) that the line is added / updated so I am not forced to do a full refresh and insert each time a line is modified.
What would be the best approach to deal with this?
say the quantity is updated, or a new country is added
You can try below update query in 3.6 mongo version.
For updating Qty for Organisation/Country Code/Period Code - Org1/Code1/201707
db.collection.update(
{ },
{ "$set": { "Product_Sales.$[org].Country.$[country].Period.$[period].Qty" : 2 } },
{ arrayFilters: [ { "org.organisation": "Org1" }, { "country.Code": "Code1" }, { "period.Code": 201707 } ] }
)
For adding new Country to Organisation Org2
db.collection.update(
{ },
{ "$push": { "Product_Sales.$[org].Country" : {"Code": "Code4","Guarantee_Years": "2Y"} } },
{ arrayFilters: [ { "org.organisation": "Org2"} ] }
)
Can be simplified to
db.collection.update(
{ "org.organisation": "Org2"},
{ "$push": { "Product_Sales.$.Country" : {"Code": "Code4","Guarantee_Years": "2Y"} } }
)
Related
Mongodb Liqbase script findOneAndUpdate for json type values
I have code that uses existing collection that I want to update name field value which is present in taskMap key how i run with run liqubase changeset for that . sample code : "changes": [ { "collectionName": "bulk_import_job_spec" }, { "findOneAndUpdate": { {"_id": 101}, [{"$set": {"task_map": {"import": {"_id": 1, "name": "Category Association"}}}}] }, { "returnNewDocument": true } ]
your questions is quite vague. Please provide some more details so that we can understand your issue.
MongoDB Project - return data only if $elemMatch Exist
Hello Good Developers, I am facing a situation in MongoDB where I've JSON Data like this [{ "id": "GLOBAL_EDUCATION", "general_name": "GLOBAL_EDUCATION", "display_name": "GLOBAL_EDUCATION", "profile_section_id": 0, "translated": [ { "con_lang": "US-EN", "country_code": "US", "language_code": "EN", "text": "What is the highest level of education you have completed?", "hint": null }, { "con_lang": "US-ES", "country_code": "US", "language_code": "ES", "text": "\u00bfCu\u00e1l es su nivel de educaci\u00f3n?", "hint": null }... { .... } ] I am projecting result using the following query : db.collection.find({ }, { _id: 0, id: 1, general_name: 1, translated: { $elemMatch: { con_lang: "US-EN" } } }) here's a fiddle for the same: https://mongoplayground.net/p/I99ZXBfXIut I want those records who don't match $elemMatch don't get returned at all. In the fiddle output, you can see that the second item doesn't have translated attribute, In this case, I don't want the second Item at all to be returned. I am using Laravel as Backend Tech, I can filter out those records using PHP, but there are lots of records returned, and I think filtering using PHP is not the best option.
You need to use $elemMatch in the first parameter db.collection.find({ translated: { $elemMatch: { con_lang: "IT-EN" } } }) MongoPlayground
Nested search using MongoDB template
I have below document in Mongo DB and I wrote a java code to get data from innermost element . For some reason its not returning me any results for it. Input data { "_id": "59036b0fa036cc28c8e07db6", "srcName":"test1", "sections": [{ "_id": "8769669696", "data": [{ "srcKey": "Bonds", "rowIdx": 0, "values": [{ "srcDesc": "Assets", "valuesNumber": 10000 }, { "srcDesc": "NonAssets", "valuesNumber": 75500 }, { "srcDesc": "liabilities", "valuesNumber": 1566 } ] }, { "srcKey": "01", "rowIdx": 1, "values": [{ "srcDesc": "NonAssets", "valuesNumber": 1566 }] } ] }] } The result I want is select valuesNumber from...where srcName="test1" AND srcKey="Bonds" AND srcDesc="Assets" Java code is as below AggregationOperation match=Aggregation.match(Criteria.where("srcName").in("test1") .and("sections.data.values.srcDesc").in("Assets") .and("sections.data.srcKey").in("Bonds")); AggregationOperation unwind1=Aggregation.unwind("sections"); AggregationOperation unwind2=Aggregation.unwind("sections.data"); AggregationOperation unwind3=Aggregation.unwind("sections.data.values"); Aggregation aggregation=Aggregation.newAggregation(match,unwind1,unwind2,unwind3,match); BasicDBObject basicDBObject=mongoTemplate.aggregate(aggregation,"InsStatData",BasicDBObject.class).getUniqueMappedResult();
It resolved my question. I just had to do a proper mapping to get Mapped results. that was not there in original code. – user3516787 just now edit
Adding Fields to an existing Array
I have another problem to solve here. Thinking in arrays sometimes could be very challenging. Here is what I am lined up with. This is what my data looks like: - { "_id": { "Firm": "ABC", "year": 2014 }, "Headings": [ { "costHead": "MNF", "amount": 500000 }, { "costHead": "SLS", "amount": 25000 }, { "costHead": "OVRHD", "amount": 100 } ] } { "_id": { "Firm": "CDF", "year": 2015 }, "Headings": [ { "costHead": "MNF", "amount": 15000 }, { "costHead": "SLS", "amount": 100500 }, { "costHead": "MNTNC", "amount": 7500 } ] } As you can see, I have a list that has a whole bunch of sub-documents. Here is what I want to do .. I need to add more elements to this "Headings" list which should be : - { "costHead": "FxdCost", "amount": "$Headings.amount (for costhead MFC) + $Headings.amount (for costhead OVRHD)" } I am unsure as to how to produce the above. Here are some challenges: - I can addToSet the new subdocument I wish to add but the problem is addToSet can only be used in the group stage - which would be expensive (unless of course there is no other way). Even if I use addToSet, I always have to use the $ operator to refer to elements that I read from my JSON file. Now the element I am trying to add here (costHead: FxdCost) is not present in my JSON file and hence I cannot use the $ operator. Does anyone have any advice on how to go about this. This is after all basic ETL.
How do I find an element in meteor.users then insert/update/upsert my data an empty array, then update if I found it? In mongodb and meteor
How do I find course_id in meteor.users then insert/update/upsert my data into "classes" (an empty array)? if cant find course_id then insert a new array, if i can then i update the array with new classes_id. Empty classes array: { "_id": "RoFFcaAfXBeR2napZ", "emails": [ { "address": "tong#gmail.com", "verified": false } ], "classes": [], "courses": [ "qwmZdgQbrZ3rmHdN8" ] } Insert new array to classes if i cant find course_id: { "_id": "RoFFcaAfXBeR2napZ", "emails": [ { "address": "tong#gmail.com", "verified": false } ], "classes": [ { "course_id": "svesvinfdsgrvnekuktndvsk", "classes_id": ["myclass1"] }, ], "courses": [ "qwmZdgQbrZ3rmHdN8" ] } Add myclass2 to classes_id if i can find course_id { "_id": "RoFFcaAfXBeR2napZ", "emails": [ { "address": "tong#gmail.com", "verified": false } ], "classes": [ { "course_id": "svesvinfdsgrvnekuktndvsk", "classes_id": ["myclass1", "myclass2"] }, ], "courses": [ "qwmZdgQbrZ3rmHdN8" ] }
To find the record that has the course ID in question: Meteor.users.find({"courses": yourVariableHoldingTheId}) is an example query. This assumes that your publication has the courses field on it (more on publishing Users stackoverflow and Meteor. From that query, you'll now have the Cursor of Users that meet your criteria. Iterate over the users and treat them as normal JS objects - check your criteria and either push to the classes subdocument, or push to the classes.$.classesId. Pushing to classes Meteor.users.update({_id: "RoFFcaAfXBeR2napZ"}, {$push: {'classes': {'course_id': 'yourGibberishHere', 'classes_id': ['test']}}}); Pushing to the classes_id Meteor.users.update({"classes.course_id": "svesvinfdsgrvnekuktndvsk"}, {$push: {"classes.$.classes_id": "myclass3"}}); tested on Mongo 3.2, your mileage may vary in meteor (2.6 or 3.2, if you're using external mongo). Older commentary points to x.$.y not working in meteor/mongo $push, not sure if this is still the case. If any of these fail, you can manipulate the object returned from the find and update it or subdocuments thereof using more accessible calls