Get Multiple Objects From Array in different Documents MongoDb - arrays

My collection coll is
/* 1 */
{
"_id" : ObjectId("566121aa4b88d840eb7d1c50"),
"batchCourseId" : ObjectId("566122ab94b792fbdf81bcf3"),
"array" : [
{
"id" : 1
},
{
"id" : 2
},
{
"id" : 3
},
{
"id" : 4
}
]
}
/* 2 */
{
"_id" : ObjectId("5661224a4b88d840eb7d1c51"),
"batchCourseId" : ObjectId("566122ab94b792fbdf81bcf3"),
"array" : [
{
"id" : 1
},
{
"id" : 7
},
{
"id" : 3
},
{
"id" : 5
}
]
}
what i need is to pull objects in array 'array' where
batchCourseId = ObjectId("566122ab94b792fbdf81bcf3")
and 2<array.id<=5
expected output is
/* 1 */
{
"_id" : ObjectId("566121aa4b88d840eb7d1c50"),
"array" : [
{
"id" : 3
},
{
"id" : 4
}
]
}
/* 2 */
{
"_id" : ObjectId("5661224a4b88d840eb7d1c51"),
"array" : [
{
"id" : 3
},
{
"id" : 5
}
]
}
already tried
db.coll.find({"batchCourseId" : ObjectId("566122ab94b792fbdf81bcf3")},
{ array: { $elemMatch: { id: { $gt: 2,$lte: 5} } } })
the output is like
/* 1 */
{
"_id" : ObjectId("566121aa4b88d840eb7d1c50"),
"array" : [
{
"id" : 3
}
]
}
/* 2 */
{
"_id" : ObjectId("5661224a4b88d840eb7d1c51"),
"array" : [
{
"id" : 3
}
]
}
close but only the first matching object in array is in result
FYI this only a sample set of data the original data is more complex and big in count
so pls let me know the best practice to do this, performance is also important
thanks in advance

You can use aggregation for achieving the same. A sample is shown below:
db.coll.aggregate(
{$match: {"batchCourseId" : ObjectId("566122ab94b792fbdf81bcf3")}},
{$unwind: '$array'},
{$match: {'array.id': { $gt: 2,$lte: 5}}},
{$group: {_id: '$_id', array: {$push : '$array'}}}
)
Result:
{ "_id" : ObjectId("5661224a4b88d840eb7d1c51"), "array" : [ { "id" : 3 }, { "id" : 5 } ] }
{ "_id" : ObjectId("566121aa4b88d840eb7d1c50"), "array" : [ { "id" : 3 }, { "id" : 4 } ] }

In MongoDB aggregation $unwind creates Cartesian_product problem so in large data set is good way to avoid $unwind.
Let's check with your example if you use $unwind in aggregation then result looks like this
db.collectionName.aggregate([
{ "$match": { "batchCourseId": ObjectId("566122ab94b792fbdf81bcf3") }},
{ "$unwind": "$array" }
])
so result of above query is :
{ "_id" : ObjectId("566121aa4b88d840eb7d1c50"), "batchCourseId" : ObjectId("566122ab94b792fbdf81bcf3"), "array" : { "id" : 1 } }
{ "_id" : ObjectId("566121aa4b88d840eb7d1c50"), "batchCourseId" : ObjectId("566122ab94b792fbdf81bcf3"), "array" : { "id" : 2 } }
{ "_id" : ObjectId("566121aa4b88d840eb7d1c50"), "batchCourseId" : ObjectId("566122ab94b792fbdf81bcf3"), "array" : { "id" : 3 } }
{ "_id" : ObjectId("566121aa4b88d840eb7d1c50"), "batchCourseId" : ObjectId("566122ab94b792fbdf81bcf3"), "array" : { "id" : 4 } }
{ "_id" : ObjectId("5661224a4b88d840eb7d1c51"), "batchCourseId" : ObjectId("566122ab94b792fbdf81bcf3"), "array" : { "id" : 1 } }
{ "_id" : ObjectId("5661224a4b88d840eb7d1c51"), "batchCourseId" : ObjectId("566122ab94b792fbdf81bcf3"), "array" : { "id" : 7 } }
{ "_id" : ObjectId("5661224a4b88d840eb7d1c51"), "batchCourseId" : ObjectId("566122ab94b792fbdf81bcf3"), "array" : { "id" : 3 } }
{ "_id" : ObjectId("5661224a4b88d840eb7d1c51"), "batchCourseId" : ObjectId("566122ab94b792fbdf81bcf3"), "array" : { "id" : 5 } }
this create multiple documents and in large documents in collections it slow the performance and increase processing time.
Instead of $unwind use $map in aggregation with aggregation-set operator and the query is as below :
db.collection.aggregate([{
"$match": {
"batchCourseId": ObjectId("566122ab94b792fbdf81bcf3")
}
}, {
"$project": {
"array": {
"$setDifference": [{
"$map": {
"input": "$array",
"as": "el",
"in": {
"$cond": {
"if": {
"$and": [{
"$gt": ["$$el.id", 2]
}, {
"$lte": ["$$el.id", 5]
}]
},
"then": "$$el",
"else": false
}
}
}
},
[false]
]
}
}
}])

Related

Update value of key in Object in nested array of objects in MongoDB

I am trying to update data of "array1.array2._id": ObjectId("627a6fab60dc3c523b396af1") and Set Name to John But it's updating in all array2's first element's name to John.
db.getCollection('tests')
.updateOne({ "array1.array2._id": ObjectId("627a6fab60dc3c523b396af1") },{ $set: { "array1.$[].array2.$.name" : "John" } })
{
"_id" : ObjectId("627a6fab60dc3c523b396aec"),
"array1" : [
{
"array2" : [
{
"_id" : ObjectId("627a6fab60dc3c523b396af1"),
"name" : "test"
},
{
"_id" : ObjectId("627a6fab60dc3c523b396af2"),
"name" : "ABC"
}
],
"_id" : ObjectId("627a6fab60dc3c523b396aed")
},
{
"array2" : [
{
"_id" : ObjectId("627a6fab60dc3c523b396af3"),
"name" : "XYZ"
},
{
"_id" : ObjectId("627a6fab60dc3c523b396af4"),
"name" : "Testing"
}
],
"_id" : ObjectId("627a6fab60dc3c523b396aee")
}
]
}
Based on this great answer by #R2D2, you can do:
db.collection.update({
"array1.array2._id": ObjectId("627a6fab60dc3c523b396af1")
},
{
$set: {
"array1.$[].array2.$[y].name": "John"
}
},
{
arrayFilters: [
{
"y._id": ObjectId("627a6fab60dc3c523b396af1")
}
]
})
As you can see on this playground example

MongoDB: find in array of objects where items are only one value

The data is like this:
{
"_id" : ObjectId("5ae9f2188857ce20f516315c"),
"meta" : {
"participants" : [
{
"gender" : [
{
"text" : "weiblich",
"id" : "LABEL.FEMALE"
}
]
},
{
"gender" : [
{
"text" : "männlich",
"id" : "LABEL.MALE"
}
]
},
{
"gender" : [
{
"text" : "weiblich",
"id" : "LABEL.FEMALE"
}
]
}
]
}
}
{
"_id" : ObjectId("5af00e1070bb5a707634cb12"),
"meta" : {
"participants" : [
{
"gender" : [
{
"text" : "männlich",
"id" : "LABEL.MALE"
}
]
},
{
"gender" : [
{
"text" : "männlich",
"id" : "LABEL.MALE"
}
]
}
]
}
}
{
"_id" : ObjectId("5af1ef01cfd317006694a6e6"),
"meta" : {
"participants" : [
{
"gender" : [
{
"text" : "weiblich",
"id" : "LABEL.FEMALE"
}
]
},
{
"gender" : [
{
"text" : "weiblich",
"id" : "LABEL.FEMALE"
}
]
}
]
}
}
So meta.participants contains some items with different properties e.g. gender with is also an array of one item (don't ask, historic reasons; it's always one item, never two and never empty).
I need a query which returns the documents which contains only male participants (the second doc 5af00e1070bb5a707634cb12).
I already tried my luck but I can't get it right.
These queries give me every doc which has a male participant:
{'meta.participants.gender.id': 'LABEL.MALE'}
{'meta.participants.gender': { $elemMatch: {id: 'LABEL.MALE'}}}
These queries give me 0 results..
{'meta.participants.gender': {id: 'LABEL.MALE'}}
{'meta.participants.gender[0]': { $elemMatch: {id: 'LABEL.MALE'}}}
Try the below:
db.collection.find({
"meta.participants": {
"$not": {
"$elemMatch": {
"gender.id": {
"$nin": [
"LABEL.MALE"
]
}
}
}
}
})
The query to retrieve documents with gender.id field do not have LABEL.FEMALE.
db.test.find( { "meta.participants.gender.id": { $ne: "LABEL.FEMALE" } } )
As such you don't need to use the $elemMatch for Single Query Condition (but, it not an error and the results will be same).

MongoDB query with elemMatch for nested array data and return only matching elements

{
"_id" : NumberLong(107),
"cnic" : NumberLong(098765),
"recordsOFGt" : [
{
"records" : [
{
"_id" : NumberLong(1),
"contactIds" : [
NumberLong(303)
],
},
{
"_id" : NumberLong(2),
"contactIds" : [
NumberLong(303),
NumberLong(304)
],
},
{
"_id" : NumberLong(3),
"contactIds" : [
NumberLong(309),
NumberLong(304)
],
},
{
"_id" : NumberLong(4),
"contactIds" : [
NumberLong(303),
NumberLong(304)
],
},
{
"_id" : NumberLong(5),
"contactIds" : [
NumberLong(303),
NumberLong(304)
],
},
]
},
"records2" : {
...
...
}
]
}
I want only record element that will be matched via _id I have tried this
db.getCollection('tempCollection').findOne(
{ 'recordsOFGt': {$elemMatch: {'records._id': 1} }},
{'recordsOFGt.$': 1}
)
this returns all elements of records array need just matching element.
this is what I want as output :
{
"records" :
{
"_id" : NumberLong(1),
"contactIds" : [
NumberLong(303)
],
}
}

Mongoose search for element in utmost sub array

My schema is as follows
{
product:[{
structure :[{
version:[{
type:[{
values:[{}]
}]
}]
}]
}]
}
Need to search fields in values array.
Actually I need to update the fields in values array. I'm unable to write query to get sub array values. How can I do that. Kindly let me know, as soon as possible.
You can use this types of query:
// match a one name
db.getCollection('test').find({"product.structure.version.type.values.name":'test'})
// match some value from an array
db.getCollection('test').find({"product.structure.version.type.values.name": {$in: [1, 'test']}})
Last query will find 3 items in the next collection:
/* 1 */
{
"_id" : ObjectId("595b9e17c482ca1b99db23a6"),
"product" : [
{
"structure" : [
{
"version" : [
{
"type" : [
{
"values" : [
{
"name" : 1
}
]
}
]
}
]
}
]
}
]
}
/* 2 */
{
"_id" : ObjectId("595b9e68f9f2fe8d79ca4c82"),
"product" : [
{
"structure" : [
{
"version" : [
{
"type" : [
{
"values" : [
{
"name" : 3
},
{
"name" : 4
},
{
"name" : 1
}
]
}
]
}
]
}
]
}
]
}
/* 3 */
{
"_id" : ObjectId("595b9e71f9f2fe8d79ca4c84"),
"product" : [
{
"structure" : [
{
"version" : [
{
"type" : [
{
"values" : [
{
"name" : 5
}
]
}
]
}
]
}
]
}
]
}
/* 4 */
{
"_id" : ObjectId("595ba08af9f2fe8d79ca4cd9"),
"product" : [
{
"structure" : [
{
"version" : [
{
"type" : [
{
"values" : [
{
"name" : 6
}
]
}
]
}
]
}
]
}
]
}
/* 5 */
{
"_id" : ObjectId("595ba0f1f9f2fe8d79ca4d00"),
"product" : [
{
"structure" : [
{
"version" : [
{
"type" : [
{
"values" : [
{
"name" : "test"
}
]
}
]
}
]
}
]
}
]
}
UPDATE:
To do an update query, you need to do something like this:
db.getCollection('test').update({"product.structure.version.type.values.name": {$in: [1, 'test']}}, {$set: {"product.$.testProp": 'some test string'}}, {multi: true})

Mongo DB array aggregation to count all array entries in a collection [duplicate]

so i have a bunch of simple documents like
{
"foos": [
ObjectId("5105862f2b5e30877c685c58"),
ObjectId("5105862f2b5e30877c685c57"),
ObjectId("5105862f2b5e30877c685c56"),
],
"typ": "Organisation",
}
and i want to find out the overall size of associated foos to documents of type "Organisation"
so i have this aggregate query
db.profil.aggregate(
[
{
$match:{
"typ":"Organisation"
}
},
{
$project: {
fooos: { $size: "$foos" }
}
}
]
)
this returns the count of all foos for each document
like :
{ "_id" : ObjectId("50e577602b5e05e74b38a6c8"), "foooos" : 1 }
{ "_id" : ObjectId("51922170975a09f363e3eef5"), "foooos" : 3 }
{ "_id" : ObjectId("51922170975a09f363e3eef8"), "foooos" : 2 }
{ "_id" : ObjectId("5175441d975ae346a3a8dff2"), "foooos" : 0 }
{ "_id" : ObjectId("5192216f975a09f363e3eee9"), "foooos" : 2 }
{ "_id" : ObjectId("5192216f975a09f363e3eeeb"), "foooos" : 3 }
{ "_id" : ObjectId("5192216f975a09f363e3eee4"), "foooos" : 2 }
{ "_id" : ObjectId("5192216f975a09f363e3eee6"), "foooos" : 2 }
{ "_id" : ObjectId("5192216f975a09f363e3eedb"), "foooos" : 2 }
{ "_id" : ObjectId("51922174975a09f363e3ef4a"), "foooos" : 1 }
{ "_id" : ObjectId("5192216f975a09f363e3eee1"), "foooos" : 1 }
{ "_id" : ObjectId("5192216e975a09f363e3eed7"), "foooos" : 2 }
{ "_id" : ObjectId("5192216f975a09f363e3eeee"), "foooos" : 3 }
is there some query that would return the summed up count for foos of all documents ?
i played arround with $sum but dont know how to combine with my query, i only do get syntax errors, it would be cool to know if this is possible
Include the $group operator pipeline stage after the $project step as follows:
db.profil.aggregate([
{ "$match":{ "typ": "Organisation" } },
{ "$project": {
"fooos": { "$size": "$foos" }
} },
{ "$group": {
"_id": null,
"count": {
"$sum": "$fooos"
}
} }
])
This will group all the input documents from the previous $project stage and applies the accumulator expression $sum on the fooos field within the group to get the total (using your last example):
This can also be done by-passing the $project pipeline as:
db.profil.aggregate([
{ "$match": { "typ": "Organisation" } },
{ "$group": {
"_id": null,
"count": {
"$sum": { "$size": "$foos" }
}
} }
])
Output
/* 0 */
{
"result" : [
{
"_id" : null,
"count" : 24
}
],
"ok" : 1
}
I know this is an old question but you can bypass project altogether if you want, so how about this?
db.profil.aggregate([
{
"$match":{ "typ": "Organisation" }
},
{
"$group":
{
"_id": null,
"count":
{
"$sum": { "$size": "$foos" }
}
}
}])
The output remains the same and it seems it's (slightly) faster.

Resources