Using 'findAndModify' on mongodb within multiple nested array (complex) - mongodb

I have the next document in a collection:
{
"_id" : ObjectId("546a7a0f44aee82db8469f6d"),
...
"valoresVariablesIterativas" : [
{
"asignaturaVO" : {
"_id" : ObjectId("546a389c44aee54fc83112e9")
},
"valoresEstaticos" : {
"IT_VAR3" : "",
"IT_VAR1" : "",
"IT_VAR2" : "asdasd"
},
"valoresPreestablecidos" : {
"IT_ASIGNATURA" : "Matemáticas",
"IT_NOTA_DEFINITIVA_ASIGNATURA" : ""
}
},
{
"asignaturaVO" : {
"_id" : ObjectId("546a3d8d44aee54fc83112fa")
},
"valoresEstaticos" : {
"IT_VAR3" : "",
"IT_VAR1" : "",
"IT_VAR2" : ""
},
"valoresPreestablecidos" : {
"IT_ASIGNATURA" : "Español",
"IT_NOTA_DEFINITIVA_ASIGNATURA" : ""
}
}
]
...
}
I want modify an element of the valoresEstaticos, I know the fields "_id", "asignaturaVO", and the key of the item valoresEstaticos that I want modify.
Which is the correct query for this?, I have this:
db.myCollection.findAndModify({
query:{"_id" : ObjectId("546a7a0f44aee82db8469f6d")},
update: {
{valoresVariablesIterativas.asignaturaVO._id: ObjectId("546a389c44aee54fc83112e9")},
{ $set: {}}
}
})
but I dont know how to build a query :(
Help me please, Thank you very much!

You can just use update.
db.myCollection.update(
{ "_id" : ObjectId("546a7a0f44aee82db8469f6d"), "valoresVariablesIterativas.asignaturaVO._id" : ObjectId("546a389c44aee54fc83112e9") },
{ "$set" : { "valoresVariablesIterativas.$.valoresEstaticos.IT_VAR3" : 99 } }
)
assuming you want to update key IT_VAR3. The key is the positional update operator $. The condition on the array in the query portion of the update is redundant for finding the document, but necessary to use the $ to update the correct array element.

Related

MongoDB querying nested documents

I have records like:
{
"_id" : ObjectId("5f99cede36fd08653a3d4e92"),
"accessions" : {
"sample_accessions" : {
"5f99ce9636fd08653a3d4e86" : {
"biosampleAccession" : "SAMEA7494329",
"sraAccession" : "ERS5250977",
"submissionAccession" : "ERA3032827",
"status" : "accepted"
},
"5f99ce9636fd08653a3d4e87" : {
"biosampleAccession" : "SAMEA7494330",
"sraAccession" : "ERS5250978",
"submissionAccession" : "ERA3032827",
"status" : "accepted"
}
}
}
}
How do I query by the mongo id in sample_accessions? I thought this should work but it doesn't. What should I be doing?
db.getCollection('collection').find({"accessions.sample_accessions":"5f99ce9636fd08653a3d4e86"})
The id is a key and check whether key is exists or not use $exists, customize response using project to get specific object
db.getCollection('collection').find(
{
"accessions.sample_accessions.5f99ce9636fd08653a3d4e86": {
$exists: true
}
},
{ sample_doc: "$accessions.sample_accessions.5f99ce9636fd08653a3d4e86" }
)
Playground

Update a json document in a mongodb database

I'm trying to update an existing document in a MongoDb. There are many explanations how to do this if you want to update or add key/value pairs on the first level. But in my use-case, I need to create with the first updateOne (with upsert option set) a document with the following structure:
{
"_id" : "1234",
"raw" : {
"meas" : {
"meas1" : {
"data" : "blabla"
}
}
}
}
In the second command, I need to add - in the same document - a "meas2" field at the level of "meas1". My desired output is:
{
"_id" : "1234",
"raw" : {
"meas" : {
"meas1" : {
"data" : "blabla"
},
"meas2" : {
"data" : "foo"
}
}
}
}
I played with statements like
updateOne({"_id":"1234"},{$set:{"raw":{"meas":{"meas2":{"data":"foo"}}}}}, {"upsert":true})
and also with $push, both variants with insert - here only the document and also insertOne, but nothing produces the desired output. Is there a MongoDb expert who could give a hint ? ... I'm sure this functionality exists... Thanks in advance!
When you update {$set: {"raw":{"meas":{"meas2":{"data":"foo"}}}} you're not adding "mesa2" to "meas" but rather you're overriting "raw" completely.
In order to change / add one field in a document refer to it with dot notations.
The command you want is updateOne({"_id": "1234"}, {$set: {"raw.meas.mesa2": { "data" : "foo" }}}, {"upsert":"true"})
You need to understand the below concept first
Set Fields in Embedded Documents, with details document check at official documentation of mongo
For your problem, just look at the below execution on the mongo shell:
> db.st4.insert({
... "_id" : "1234",
... "raw" : {
... "meas" : {
... "meas1" : {
... "data" : "blabla"
... }
... }
... }
... })
WriteResult({ "nInserted" : 1 })
> db.st4.find()
{ "_id" : "1234", "raw" : { "meas" : { "meas1" : { "data" : "blabla" } } } }
>
> // Below query will replace the raw document with {"meas":{"meas2":{"data":"foo"}}}, will not add
> //db.st4.updateOne({"_id":"1234"},{$set:{"raw":{"meas":{"meas2":{"data":"foo"}}}}}, {"upsert":true})
>// By using the dot operator, you actually write the values inside the documents i.e you are replacing or adding at raw.meas.mesa2 i.e inside the document of mesa2.
> db.st4.updateOne({"_id":"1234"},{$set: {"raw.meas.mesa2": { "data" : "foo" }}}, {"upsert":"true"})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.st4.find().pretty()
{
"_id" : "1234",
"raw" : {
"meas" : {
"meas1" : {
"data" : "blabla"
},
"mesa2" : {
"data" : "foo"
}
}
}
}
>

Retrieving value of an emedded object in mongo

Followup Question
Thanks #4J41 for your spot on resolution. Along the same lines, I'd also like to validate one other thing.
I have a mongo document that contains an array of Strings, and I need to convert this particular array of strings into an array of object containing a key-value pair. Below is my curent appraoch to it.
Mongo Record:
Same mongo record in my initial question below.
Current Query:
templateAttributes.find({platform:"V1"}).map(function(c){
//instantiate a new array
var optionsArray = [];
for (var i=0;i< c['available']['Community']['attributes']['type']['values'].length; i++){
optionsArray[i] = {}; // creates a new object
optionsArray[i].label = c['available']['Community']['attributes']['type']['values'][i];
optionsArray[i].value = c['available']['Community']['attributes']['type']['values'][i];
}
return optionsArray;
})[0];
Result:
[{label:"well-known", value:"well-known"},
{label:"simple", value:"simple"},
{label:"complex", value:"complex"}]
Is my approach efficient enough, or is there a way to optimize the above query to get the same desired result?
Initial Question
I have a mongo document like below:
{
"_id" : ObjectId("57e3720836e36f63695a2ef2"),
"platform" : "A1",
"available" : {
"Community" : {
"attributes" : {
"type" : {
"values" : [
"well-known",
"simple",
"complex"
],
"defaultValue" : "well-known"
},
[......]
}
I'm trying to query the DB and retrieve only the value of defaultValue field.
I tried:
db.templateAttributes.find(
{ platform: "A1" },
{ "available.Community.attributes.type.defaultValue": 1 }
)
as well as
db.templateAttributes.findOne(
{ platform: "A1" },
{ "available.Community.attributes.type.defaultValue": 1 }
)
But they both seem to retrieve the entire object hirarchy like below:
{
"_id" : ObjectId("57e3720836e36f63695a2ef2"),
"available" : {
"Community" : {
"attributes" : {
"type" : {
"defaultValue" : "well-known"
}
}
}
}
}
The only way I could get it to work was with find and map function, but it seems to be convoluted a bit.
Does anyone have a simpler way to get this result?
db.templateAttributes.find(
{ platform: "A1" },
{ "available.Community.attributes.type.defaultValue": 1 }
).map(function(c){
return c['available']['Community']['attributes']['type']['defaultValue']
})[0]
Output
well-known
You could try the following.
Using find:
db.templateAttributes.find({ platform: "A1" }, { "available.Community.attributes.type.defaultValue": 1 }).toArray()[0]['available']['Community']['attributes']['type']['defaultValue']
Using findOne:
db.templateAttributes.findOne({ platform: "A1" }, { "available.Community.attributes.type.defaultValue": 1 })['available']['Community']['attributes']['type']['defaultValue']
Using aggregation:
db.templateAttributes.aggregate([
{"$match":{platform:"A1"}},
{"$project": {_id:0, default:"$available.Community.attributes.type.defaultValue"}}
]).toArray()[0].default
Output:
well-known
Edit: Answering the updated question: Please use aggregation here.
db.templateAttributes.aggregate([
{"$match":{platform:"A1"}}, {"$unwind": "$available.Community.attributes.type.values"},
{$group: {"_id": null, "val":{"$push":{label:"$available.Community.attributes.type.values",
value:"$available.Community.attributes.type.values"}}}}
]).toArray()[0].val
Output:
[
{
"label" : "well-known",
"value" : "well-known"
},
{
"label" : "simple",
"value" : "simple"
},
{
"label" : "complex",
"value" : "complex"
}
]

MongoDb : Update a Record & push to an array. Cannot update 'addresses.0' and 'addresses.0.insertupdate' at the same time

I have a collection names with this schema.
{
name: "A1",
addresses :
[
{
add1 : "a1",
add2 : "a2",
insertupdate:[
{
"mode" : "i" ,
"user" : "abcd"
}
]
}
,
{
add1 : "a3",
add2 : "a4",
insertupdate:[
{
"mode" : "i",
"user" : "pqrs"
}
]
}
],
insertupdate:[
{
"mode" : "i",
"user" : "pqrs"
}
]
}
What I am trying to do :
I want to update record add1 = "a1" as add2 = "a5" & push a record inside addresses.insertupdate as well as insertupdate.
What i tried :
db.names.update({name:"A1",addresses.add1:"a1"},
{
$set : {
addresses.$ :
{
"add2":"a5"
}
},
$push : {
"insertupdate" : {"mode":"u","user":"xyz"},
"addresses.$.insertupdate" : {"mode":"u","user":"xyz"}
}
}
);
Error I got :
Cannot update 'addresses.0' and 'addresses.0.insertupdate' at the same
time
Edit :
This command was successful. However it wont let me set my values. i.e. I need a way out to use a set & push with the positional operator at the same time.
db.names.update(
{"name":"A1", "addresses.add1":"a1"},
{$push:{
"insertupdate":{"mode":"u","user":"xyz"},
"addresses.$.insertupdate":{"mode":"u","user":"xyz"}
}
})
A comment in one of my questions pointed me to the answer mongodb update using positional operator $ removes other fields :
db.names.update({name:"A1",addresses.add1:"a1"},
{
$set : {
"addresses.$.add2" : "a5"
},
$push : {
"insertupdate" : {"mode":"u","user":"xyz"},
"addresses.$.insertupdate" : {"mode":"u","user":"xyz"}
}
}
);

Mongo query to return distinct count, large documents

I need to be able to get a count of distinct 'transactions' the problem I'm having is that using .distinct() comes back with an error because the documents too large.
I'm not familiar with aggregation either.
I need to be able to group it by 'agencyID' as you see below there are 2 different agencyID's
I need to be able to count transactions where the agencyID is 01721487 etc
db.myCollection.distinct("bookings.transactions").length
this doesn't work as I need to be able to group by agencyID and if there are too many results I get an error saying it's too large.
{
"_id" : ObjectId("5624a610a6e6b53b158b4744"),
"agencyID" : "01721487",
"paxID" : "-530189664",
"bookings" : [
{
"bookingID" : "24232",
"transactions" : [
{
"tranID" : "001",
"invoices" : [
{
"invNum" : "1312",
"type" : "r",
"inv_date" : "20150723",
"inv_time" : "0953",
"inv_val" : -300
}
],
"tranType" : "Fee",
"tranDate" : "20150723",
"tranTime" : "0952",
"opCode" : "admin",
"udf_1" : "j s"
}
],
"acctID" : "acct11",
"agt_id" : "xy"
}
],
"title" : "",
"firstname" : "",
"surname" : "f bar"
}
I've also tried this but it didn't work for me.
thank you for text data -
this is something you could play with:
db.kieron.aggregate([{
$unwind : "$bookings"
}, {
$match : {
"bookings.transactions" : {
$exists : true,
$not : {
$size : 0
}
}
}
}, {
$group : {
_id : "$agencyID",
count : {
$sum : {
$size : "$bookings.transactions"
}
}
}
}
])
as there is nested array we need to unwind it first, and then we can check size of inner array.
Happy reporting!