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

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).

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

Update array at specific index by other filed in MongoDB

I have a collection, consist of name and data.
data is an array with 2 elements, each element is the object with code and qty.
{
"_id" : ObjectId("605c666a15d2612ed0afedd2"),
"name" : "Anna",
"data" : [
{
"code" : "a",
"qty" : 3
},
{
"code" : "b",
"qty" : 4
}
]
},
{
"_id" : ObjectId("605c666a15d2612ed0afedd3"),
"name" : "James",
"data" : [
{
"code" : "c",
"qty" : 5
},
{
"code" : "d",
"qty" : 6
}
]
}
I want to update the code of the first element to name of its document. The result I want is
{
"_id" : ObjectId("605c666a15d2612ed0afedd2"),
"name" : "Anna",
"data" : [
{
"code" : "Anna",
"qty" : 3
},
{
"code" : "b",
"qty" : 4
}
]
},
{
"_id" : ObjectId("605c666a15d2612ed0afedd3"),
"name" : "James",
"data" : [
{
"code" : "James",
"qty" : 5
},
{
"code" : "d",
"qty" : 6
}
]
}
I just google to find how to:
update array at a specific index (https://stackoverflow.com/a/34177929/11738185)
db.Collection.updateMany(
{ },
{
$set:{
'data.0.code': '$name'
}
}
)
But the code of the first element in data array is a string '$name', not a value (Anna, James)
{
"_id" : ObjectId("605c666a15d2612ed0afedd2"),
"name" : "Anna",
"data" : [
{
"code" : "$name",
"qty" : 3
},
{
"code" : "b",
"qty" : 4
}
]
},
{
"_id" : ObjectId("605c666a15d2612ed0afedd3"),
"name" : "James",
"data" : [
{
"code" : "$name",
"qty" : 5
},
{
"code" : "d",
"qty" : 6
}
]
}
update a field by the value of another field. It takes me to use pipeline updating (https://stackoverflow.com/a/37280419/11738185): the second param of updateMany is array (pipeline)
db.Collection.updateMany(
{ },
[{
$set:{
'data.0.code': '$name'
}
}]
)
and It adds field 0 to each element in data array
{
"_id" : ObjectId("605c666a15d2612ed0afedd2"),
"name" : "Anna",
"data" : [
{
"0" : {
"code" : "Anna"
},
"code" : "a",
"qty" : 3
},
{
"0" : {
"code" : "Anna"
},
"code" : "b",
"qty" : 4
}
]
},
{
"_id" : ObjectId("605c666a15d2612ed0afedd3"),
"name" : "James",
"data" : [
{
"0" : {
"code" : "James"
},
"code" : "c",
"qty" : 5
},
{
"0" : {
"code" : "James"
},
"code" : "d",
"qty" : 6
}
]
}
I can't find the solution for this case. Could anyone to help me? How can I update array at fixed index by other field. Thanks for reading!
1. update array at a specific index
You can't use internal fields as value of another fields, it will work only when you have external value to update like { $set: { "data.0.code": "Anna" } }.
2. update a field by the value of another field
Update with Aggregation pipeline can't allow to access data.0.code syntax.
You can try using $reduce in update with aggregation pipeline,
$reduce to iterate loop of data array, set empty array in initialValue of reduce, Check condition if initialValue array size is zero then replace code with name and merge with current object using $mergeObjects, else return current object,
$concatArrays to concat current object with initialValue array
db.collection.update({},
[{
$set: {
data: {
$reduce: {
input: "$data",
initialValue: [],
in: {
$concatArrays: [
"$$value",
[
{
$cond: [
{ $eq: [{ $size: "$$value" }, 0] },
{ $mergeObjects: ["$$this", { code: "$name" }] },
"$$this"
]
}
]
]
}
}
}
}
}],
{ multi: true }
)
Playground
I think easier would be another way.
Just save the model before and use it for updating after
var annaModel = nameModel.findOne({_id: "605c666a15d2612ed0afedd2" })
nameModel.findOneAndUpdate({_id: "605c666a15d2612ed0afedd2"},{$set:{'data.0.code': annaModel.name}})

How to match and retrieve specific Sub-document value from Mongo

How can I search and retrieve only "Stats.item.id" from this collection who have greater than zero "Stats.item.p" value. I am also facing problem in unwinding this collection.
{
"_id" : "8643",
"Stats" : [
{
"date" : ISODate("2014-02-01"),
"Stats" : {
"item" : [
{
"id" : "4356"
},
{
"id" : "9963",
"p" : NumberInt(1)
}
]
}
}
]
}
{
"_id" : "8643",
{
"date" : ISODate("2014-02-01"),
"Stats" : {
"item" : [
{
"id" : "9963",
"p" : NumberInt(1)
}
}
This is the output I expect. Can anyone help me write this aggregation? oooooooooooooooooooooooooooooooooooooooooooooo ooooooooooooooooooooooooo oooooooooooooooooooo oooooooooooo oooooooo
Hope this aggregation query will work
db.collection.aggregate([
{$unwind:'$Stats'},
{$unwind:'$Stats.Stats'},
{$unwind:'$Stats.Stats.item'},
{$match:{
'Stats.Stats.item.p':{$gt:0}
}},
{$group:{
_id:{
date:'$Stats.date'
},
item:{$push:'$Stats.Stats.item'},
_ids:'$_id'
}},
{$group:{
_id:{_ids:'$_ids',
date:'$_id.date'},
Stats:{$push:{
item:'$item'
}},
}},
{$project:{
_id:'$_id._ids',
Stats:{
date:'$_id.date'
Stats:'$Stats'
}
}}
])
Use $elemMAtch for searching in the array.
db.getCollection('CollectionName').find({
"Stats": {
"$elemMatch": {
"Stats.item": {
"$elemMatch": {
"p": 1
}
}
}
}
})

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})

MongoDB: Find all matched array element from single document

I have a mongodb document like this,
{
"_id" : ObjectId("4e8ae86d08101908e1000001"),
"eId": 101,
"about": "test",
"tags" : [
{"name": "jana"},
{"name":"bala"},
{"name":"jk"},
{"name":"charles"}
]
}
I need to find all matched array elements, where the name matched with given array.
db.coll.find({"tags": {"$elemMatch": {"name": {"$in": [/^jana/i, /^charles/i] }}}})
for this query i got the following result
{
"_id" : ObjectId("4e8ae86d08101908e1000001"),
"tags" : [
{
"name" : "jana"
}
]
}
$elemMatch query only return the first matched element, but i want all the matched array element like this,
{
"_id" : ObjectId("4e8ae86d08101908e1000001"),
"tags" : [
{
"name" : "jana"
},
{
"name" : "charles"
}
]
}
Is it possible to get the result like this?
note: i don't want any others fields, I want only the matched array elements along with _id
You can use MongoDB Aggregation Pipeline:
db.coll.aggregate([
{'$unwind': '$tags'},
{'$match':
{"tags.name":
{"$in": [/^jana/, /^charles/i] }
}
},
{'$group':
{
'_id': '$_id',
'tags':
{'$push': '$tags'}
}
}
])
Result : -
{
"result" : [
{
"_id" : ObjectId("5538b214706a90c718f75a41"),
"tags" : [
{
"name" : "jana"
},
{
"name" : "charles"
}
]
}
],
"ok" : 1
}

Resources