MongoDb fetch subset instead of whole record - mongodb

I have a MongoDB document structure like this:
[
{
"locale":"en",
"translations":[
{
"name":"translation1",
"value":"enValue"
},
{
"name":"translation2",
"value":"enValue"
},
{
"name":"translation3",
"value":"enValue"
}
]
},
{
"locale":"ru",
"translations":[
{
"name":"translation1",
"value":"ruValue"
},
{
"name":"translation2",
"value":"ruValue"
},
{
"name":"translation3",
"value":"ruValue"
}
]
}
]
and I need to get the translation with name translation1 for locale en. I'm trying to do it like this: db.translations.find({"locale" : "en", "translation.name": "translation1"} ) but it returning whole locale row, with all translations instead of just translation1. I'm new to MongoDB, what I'm doing wrong?

you can use $elemMatch for this.
db.translations.find({"locale" : "en"},
{ translations: { $elemMatch: { name: "translation1" } } } )
Result:
{
"_id" : ObjectId("5e845ba1005e625a6237d2e0"),
"translations" : [
{
"name" : "translation1",
"value" : "enValue"
}
]
}

Related

Query nested array from document

Given the following document data in collection called 'blah'...
[
{
"_id" : ObjectId("60913f55987438922d5f0db6"),
"procedureCode" : "code1",
"description" : "Description 1",
"coding" : [
{
"system" : "ABC",
"code" : "L111"
},
{
"system" : "DEFG",
"code" : "S222"
}
]
},
{
"_id" : ObjectId("60913f55987438922d5f0dbc"),
"procedureCode" : "code2",
"description" : "Description 2",
"coding" : [
{
"system" : "ABC",
"code" : "L999"
},
{
"system" : "DEFG",
"code" : "X3333"
}
]
}
]
What I want to get is all of the coding elements where system is ABC for all parents, and an array of codes like so.
[
{ "code": "L111" },
{ "code": "L999" },
]
If I use db.getCollection('blah').find({"coding.system": "ABC"}) I get the parent document with any child in the coding array of ICD.
If I use...
db.getCollection("blah")
.find({ "coding.system": "ABC" })
.projection({ "coding.code": 1 })
I do get the parent documents which have a child with a system of "ABC", but the coding for "DEFG" seems to come along for the ride too.
{
"_id" : ObjectId("60913f55987438922d5f0db6"),
"coding" : [
{
"code" : "L989"
},
{
"code" : "S102"
}
]
},
{
"_id" : ObjectId("60913f55987438922d5f0dbc"),
"coding" : [
{
"code" : "L989"
},
{
"code" : "X382"
}
]
}
I have also tried experimenting with:
db.getCollection("blah").aggregate(
{ $unwind: "$coding" },
{ $match: { "system": "ICD" } }
);
.. as per this page: mongoDB query to find the document in nested array
... but go no where fast with that approach. i.e. no records at all.
What query do I need, please, to achieve something like this..?
[
{ "code": "L111" },
{ "code": "L999" },
...
]
or even better, this..?
[
"L111",
"L999",
...
]
db.collection.aggregate([
{
$match: { "coding.system": "ABC" }
},
{
$unwind: "$coding"
},
{
$match: { "coding.system": "ABC" }
},
{
$project: { code: "$coding.code" }
}
])
mongoplayground
db.collection.aggregate([
{
$match: { "coding.system": "ABC" }
},
{
$unwind: "$coding"
},
{
$match: { "coding.system": "ABC" }
},
{
$group: {
_id: null,
coding: { $push: "$coding.code" }
}
}
])
mongoplayground
Instead of $unwind, $match you can also use $filter:
db.collection.aggregate([
{ $match: { "coding.system": "ABC" } },
{
$project: {
coding: {
$filter: {
input: "$coding",
cond: { $eq: [ "$$this.system", "ABC" ] }
}
}
}
}
])

How can I remove an element that is contained in the third level of an array?

my database has a structure like this:
{
"universe": "comics",
"saga": [
{
"name": "x-men",
"characters": [
{
"character": "wolverine",
"powers": [
{
"power": "self-recovery"
},
{
"power": "Super strength"
},
{
"power": "steels claws"
}
]
},
{
"character": "cyclops",
"powers": [
{
"power": "rays"
},
{
"power": "Super strength"
}
]
}
]
}
]
},
{
"universe": "comics",
"saga": [
{
"name": "spiderman",
"characters": [
{
"character": "venom",
"powers": [
{
"power": "Super strength"
}
]
}
]
}
]
}
I basically want to learn how to do operations with complex arrays, this time I think I will learn too much if I get the answer to this question.
I want to delete the objects where "power:"self-recovery"
something like $.saga.characters.$.powers
I don't know how to do it because of the number of levels this property is under the main root.
normally i would use something like that:
db.mydb.update(
{
saga: {
$elemMatch: { saga.characters.$ },
},
},
{ $pull: { powers: { power: "Super strength"
} }},
{
new: true,
multi:true
},
for this example it should delete as many objects where {" power ":" self-recovery"} (in this case, only one object is deleted, which is where the character is wolverine)
but i don't know how to do what i need.
Try the positional all $[] operator in MongoDb 3.6+
var query = {
universe: 'comics'
};
var update = {
$pull: {
'saga.$[].characters.$[].powers': {
power: 'self-recovery'
}
}
};
var options = {
multi: true
};
db.collection.update(query, update, options);
db.test.update(
{
"saga.characters.powers": {
"$elemMatch": {
"power": "self-recovery"
}
}
},
{
"$pull": {
"saga.$[].characters.$.powers": {
"power":"self-recovery"
}
}
}
)
It removes the respective power object.It results
/* 1 */
{
"_id" : ObjectId("5f11e25a9e001b53e39985fd"),
"universe" : "comics",
"saga" : [
{
"name" : "x-men",
"characters" : [
{
"character" : "wolverine",
"powers" : [
{
"power" : "Super strength"
},
{
"power" : "steels claws"
}
]
},
{
"character" : "cyclops",
"powers" : [
{
"power" : "rays"
},
{
"power" : "Super strength"
}
]
}
]
}
]
}
Kindly check and let me know missing things

Filter keys not in collection

How do we find keys which do not exist in collection.
Given an input list of keys ['3321', '2121', '5647'] , i want to return those that do not exist in the collection :
{ "_id" : { "$oid" : "5e2993b61886a22f400ea319" }, "scrip" : "5647" }
{ "_id" : { "$oid" : "5e2993b61886a22f400ea31a" }, "scrip" : "3553" }
So the expected output is ['3321', '2121']
This aggregation gets the desired output (works with MongoDB version 3.4 or later):
INPUT_ARRAY = ['3321', '2121', '5647']
db.test.aggregate( [
{
$match: {
scrip: {
$in: INPUT_ARRAY
}
}
},
{
$group: {
_id: null,
matches: { $push: "$scrip" }
}
},
{
$project: {
scrips_not_exist: { $setDifference: [ INPUT_ARRAY, "$matches" ] },
_id: 0
}
}
] )
The output:
{ "scrips_not_exist" : [ "3321", "2121" ] }

Mongo aggregation to collect array elements based on field name

I have an aggregated mongo document like below. There are two different batches ("-Minor" and "-Major"), and each batch has "batchElements" too.
{
"_id" : "123",
"info" : {
"batch" : "Batch1-Minor"
},
"batchElements" : {
"elements" : [
{ }, { }, .... { }
]
}
},
{
"_id" : "123",
"info" : {
"batch" : "Batch2-Minor"
},
"batchElements" : {
"elements" : [
{ }, { }, .... { }
]
}
},
{
"_id" : "123",
"info" : {
"batch" : "Batch3-Major"
},
"batchElements" : {
"elements" : [
{ }, { }, .... { }
]
}
},
{
"_id" : "123",
"info" : {
"batch" : "Batch4-Major"
},
"batchElements" : {
"elements" : [
{ }, { }, .... { }
]
}
}
How can I collect all "batchElements" of "-Minor" and "-Major" and create a document as below;
Output:
{
"_id" : "123",
"minorElements" : [
[{}, {}, {}, ..... {} ], // elements of "Batch1-Minor"
[{}, {}, {}, ..... {} ], // elements of "Batch2-Minor"
... // elements of "BatchN-Minor"
],
"majorElements" : [
[{}, {}, {}, ..... {} ], // elements of "Batch3-Major"
[{}, {}, {}, ..... {} ], // elements of "Batch4-Major"
... // elements of "BatchN-Major"
]
}
You can start with $split to get the "type" of your batch as part of your $group _id. Then you can run another $group to make minor and major parts of the same document. In the last step you need $replaceRoot along with $arrayToObject to promote both arrays into root level.
db.collection.aggregate([
{
$group: {
_id: {
id: "$_id",
type: { $arrayElemAt: [ { $split: [ { $toLower: "$info.batch" }, "-" ] }, 1 ] }
},
docs: { $push: "$batchElements.elements" }
}
},
{
$group: {
_id: "$_id.id",
data: { $push: { k: { $concat: ["$_id.type","Elements"] }, v: "$docs" } }
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [ { _id: "$_id" }, { $arrayToObject: "$data" } ]
}
}
}
])
Mongo Playground

Update subobject in mongodb

This is what I have in my db.
{
"_id": { "$oid" : "1111" },
"gallery": {
"images": [
{
"image": "test1.jpg",
"_id": { "$oid" : "1111a" }
},
{
"image": "test2.jpg",
"_id": { "$oid" : "1111b" }
},
{
"image": "test3.jpg",
"_id": { "$oid" : "1111c" }
}
]
}
}
,{
"_id": { "$oid" : "2222" },
"gallery": {
"images": [
{
"image": "test1.jpg",
"_id": { "$oid" : "2222a" }
}
]
}
}
I would like to update the second element (image:"test2.jpg") of the first element (_id:"1111").
The result should be
...
{
"image": "test2new.jpg",
"_id": { "$oid" : "1111b" }
},
...
I have the _id of the second image "1111b".
How can I do it?
UPDATE
I tried this query, but it doesn't work.
{
'_id':{'$oid' : '1111' }
,'gallery.image': $elemMatch:{ '_id':{'$oid':'1111b' } }
}
,{
$set:{ 'gallery.images.$.image':'test2new.jpg' }
}
SOLUTION
_id without quotes and without add { "$oid" :
{
{ _id : '1111' }
,{ 'gallery.image': $elemMatch:{ _id:'1111b' } }
}
,{
$set:{ 'gallery.images.$.image':'test2new.jpg' }
}
You can use the $ operator with update.Assuming your collection is named images you can use the following query:
db.images.update({'_id.oid':'1111','gallery.images':{'$elemMatch':{'image':'test2.jpg'}}},{'$set':{'gallery.images.$.image':'test2new.jpg'}})
You can read more about it here : http://docs.mongodb.org/manual/core/update/#update-a-document-element-without-specifying-its-position