MongoDB, how to query nested Document/object/field in tree like structure - mongodb

I have following document structure stored in Mongodb. Please note "next" is an array.
{
"id": 1,
"pricing": [
{
"name": "name1",
"value": "v1",
"next": [
{
"name": "name2",
"value": "v2",
"next": [
{
"name": "name3",
"value": "v3",
"next": [
]
}
]
}
]
}
]
}
How can I find the eg. name=name3 or any arbitrary value from it? Not knowing if it exists or not.

You can match the field pricing.next.next.name and the value name3 like this.
db.collection.find({
"pricing.next.next.name": "name3"
})
So it will return the document that contains the value name3 inside the two arrays.
Mongo Playground example here
Your question is not explained too well, so, maybe you mean, how to get only the field name after querying by name. Note that you can use other field like value to query the document.
Then, you have to do this:
db.collection.find({
"pricing.next.next.name": "name3",
},
{
"pricing.next.next.name": 1
})
And mongo Playground example here

Related

MongoDB How to find and update data in a nested structure

I'm having trouble with my mongoDB (v3.6.4), below is what my data looks like right now. I need to find (and update) the "text" value for a certain element in "second_list", i.e. return "hello" and change it to "hello world " in next step.
{
"_id": ObjectId("xxxxxxxxxxxxx"),
"top_list": [
{
"create_time": "2019-06-10 15:56:46",
"second_list": [
{
"name": "v1",
"text": "hello"
},
{
"name": "v2",
"text": "good morning"
},
{
"name": "v3",
"text": "bye"
}
]
}
]
}
i have tried this query
db.myCollection.find(
{'top_list.second_list.name':'v1'},
{"top_list.second_list":1,"_id":0}
)
but it returned the whole of "second_list". What i want should be
{
"name": "v1",
"text": "hello"
}
or just the string "hello".
This syntax works for me to find and update a value
db['myCollection'].findAndModify({query:{_id: ObjectId("xxxxxxxxxxxxx")}, update: {$set: {"top_list.second_list.0.text":"someNewText"}}})
The 0 in top_list.second_list.0.text is the array index you're wanting to access
Mongodb Has function Called FindAndModify
and your query should be like this
and the $ array operators in this link will help to modify what you want
Like $elemmatch

How can I count all possible subdocument elements for a given top element in Mongo?

Not sure I am using the right terminology here, but assume following oversimplified JSON structure available in Mongo :
{
"_id": 1234,
"labels": {
"label1": {
"id": "l1",
"value": "abc"
},
"label3": {
"id": "l2",
"value": "def"
},
"label5": {
"id": "l3",
"value": "ghi"
},
"label9": {
"id": "l4",
"value": "xyz"
}
}
}
{
"_id": 5678,
"labels": {
"label1": {
"id": "l1",
"value": "hjk"
},
"label5": {
"id": "l5",
"value": "def"
},
"label10": {
"id": "l10",
"value": "ghi"
},
"label24": {
"id": "l24",
"value": "xyz"
}
}
}
I know my base element name (labels in the example), but I do not know the various sub elements I can have (so in this case the labelx names).
How can I group / count the existing elements (like as if I would be using a wildcard) so I would get some distinct overview like
"label1":2
"label3":1
"label5":2
"label9":1
"label10":1
"label24":1
as a result? So far I only found examples where you actually need to know the element names. But I don't know them and want to find some way to get all possible sub element names for a given top element for easy review.
In reality the label names can be pretty wild, I used labelx for readability in the example.
You can try below aggregation in 3.4.
Use $objectToArray to transform object to array of key value pairs followed by $unwind and $group on key to count occurrences.
db.col.aggregate([
{"$project":{"labels":{"$objectToArray":"$labels"}}},
{"$unwind":"$labels"},
{"$group":{"_id":"$labels.k","count":{"$sum":1}}}
])

MongoDb query - aggregation, group, filter, max

I am trying to figure out specific mongoDb query, so far unsuccessfully.
Documents in my collections looks someting like this (contain more attributes, which are irrelevant for this query):
[{
"_id": ObjectId("596e01b6f4f7cf137cb3d096"),
"code": "A",
"name": "name1",
"sys": {
"cts": ISODate("2017-07-18T12:40:22.772Z"),
}
},
{
"_id": ObjectId("596e01b6f4f7cf137cb3d097"),
"code": "A",
"name": "name2",
"sys": {
"cts": ISODate("2017-07-19T12:40:22.772Z"),
}
},
{
"_id": ObjectId("596e01b6f4f7cf137cb3d098"),
"code": "B",
"name": "name3",
"sys": {
"cts": ISODate("2017-07-16T12:40:22.772Z"),
}
},
{
"_id": ObjectId("596e01b6f4f7cf137cb3d099"),
"code": "B",
"name": "name3",
"sys": {
"cts": ISODate("2017-07-10T12:40:22.772Z"),
}
}]
What I need is to get current versions of documents, filtered by code or name, or both. Current version means that from two(or more) documents with same code, I want pick the one which has latest sys.cts date value.
So, result of this query executed with filter name="name3" would be the 3rd document from previous list. Result of query without any filter would be 2nd and 3rd document.
I have an idea how to construct this query with changed data model but I was hoping someone could lead me right way without doing so.
Thank you

MongoDB, remove nested doc in an array

I have the following structure in MongoDB and I try to remove the documents that contains specific tags. I can't seem to be able to get the $pull work.
In this example, I would like to pull the nested doc that has has tags :["BB"]
Any help will be appreciated !
{
"_id": 123,
"socialItems": {
"facebook": [{
"name": "firstFacebook",
"id": 2
}, {
"name": "secondFB",
"id": 43
}],
"instagram": [{
"name": "firstNstagram",
"id": 4
}],
"pc": [{
"name": "firstPC",
"id": 55,
"tags": [
"ab"
]
}, {
"name": "secondPC",
"id": 66,
"tags": [
"BB"
]
}]
}
}
I assume you are trying to drop the nested 'pc' doc, from the array? You also don't mention if you're using a specific driver for this, so I've assumed you're running this in the Mongo shell.
The following will remove documents from the 'pc' property, when containing the 'BB' tag.
db.collectionName.update({'socialItems.pc.tags': 'BB'}, {$pull: {'socialItems.pc': {tags: 'BB'}}})

How to update the Embedded Data which is inside of another Embedded Data?

I have document like below in MongoDB:
{
"_id": "test",
"tasks": [
{
"Name": "Task1",
"Parameter": [
{
"Name": "para1",
"Type": "String",
"Value": "*****"
},
{
"Name": "para2",
"Type": "String",
"Value": "*****"
}
]
},
{
"Name": "Task2",
"Parameter": [
{
"Name": "para1",
"Type": "String",
"Value": "*****"
},
{
"Name": "para2",
"Type": "String",
"Value": "*****"
}
]
}
]
}
There is Embedded Data Structure (Parameter) inside of another Embedded Data Structure (Tasks). Now I want to update the para1 in Task1's Parameter.
I have tried many ways but I can only use query tasks.Parameter.name to find the para1 but cannot update it. the example in the doc are using .$. to update the value in a Embedded Data Structure but it doesn't work in my case.
Anyone have any ideas ?
MongoDB currently only supports the positional operator once, and only for the top level array. There is a ticket SERVER-831 to change this behavior for your use case. You can follow the issue there and up vote it.
However, you might be able to change your approach to accomplish what you want to do. One way is to change your schema. Collapse the tasks name into the array so the document looks like this:
{
_id:test,
tasks:
[
{
Task:1
Name:para1,
Type:String,
Value:*****
},
{
Task:1
Name:para2,
Type:String,
Value:*****
},
{
Task:2
Name:para1,
Type:String,
Value:*****
},
{
Task:2
Name:para2,
Type:String,
Value:*****
}
]
}
Another approach that may work for you is to use $pull and $push. For instance something like this to replace a task (this assumes that tasks.Parameter.Name is unique to an array of Parameters):
db.test2.update({$and: [{"tasks.Name": "Task3"}, {"tasks.Parameter.Name":"para1"}]}, {$pull: {"tasks.$.Parameter": {"Name": "para1"}}})
db.test2.update({"tasks.Name": "Task3"}, {$push: {"tasks.$.Parameter": {"Name": "para3", Type: "String", Value: 1}}})
With this solution you need to be careful with regard to concurrency, as there will be a brief moment where the document doesn't exist.