This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
MongoDB updating fields in nested array
I have data like:
{
"_id" : ObjectId("4f855061dd53351011000b42"),
"act_mgr" : [{ "sales" : {"agent" : ["rohan#walkover.in" ], "last_interacted" : "rohan#walkover.in" } } ],
"email" : "aman#asasas.com", "name" : "Aman",
"sales" : [{"sno" : 1, "message" : "description","status" : "open"},{"sno" : 12,"message" : "assad","status" :"open"}]
}
I want to add new agent and update last_interacted in act_mgr:sales something like that
"act_mgr" : [{ "sales" : {"agent" : ["rohan#walkover.in","abc#walkover.in" ],
"last_interacted" : "abc#walkover.in" } } ]
Also if I add new act_mgr like developer then it would be like
"act_mgr" : [{ "sales" : {"agent" : ["rohan#walkover.in","abc#walkover.in" ], "last_interacted" : "abc#walkover.in" } },
{ "developer" : {"agent" : ["newdeveloper#walkover.in" ], "last_interacted" : "newdeveloper#walkover.in" } } ]
I dont know how to add these fields
You can update the embedded "sales" document inside of the "act_mgr" array with the following update statement:
> db.sales.update({"act_mgr.sales.last_interacted":"rohan#walkover.in"}, {$push:{"act_mgr.$.sales.agent":"abc#walkover.in"}, $set:{"act_mgr.$.sales.last_interacted":"abc#walkover.in"}})
> db.sales.find().pretty()
{
"_id" : ObjectId("4f855061dd53351011000b42"),
"act_mgr" : [
{
"sales" : {
"agent" : [
"rohan#walkover.in",
"abc#walkover.in"
],
"last_interacted" : "abc#walkover.in"
}
}
],
"email" : "aman#asasas.com",
"name" : "Aman",
"sales" : [
{
"sno" : 1,
"message" : "description",
"status" : "open"
},
{
"sno" : 12,
"message" : "assad",
"status" : "open"
}
]
}
>
You can add the embedded document containing the "developer" information to the array like so:
> db.sales.update({"_id" : ObjectId("4f855061dd53351011000b42")}, {$push:{"act_mgr":{ "developer" : {"agent" : ["newdeveloper#walkover.in" ], "last_interacted" : "newdeveloper#walkover.in" } }}})
> db.sales.find().pretty()
{
"_id" : ObjectId("4f855061dd53351011000b42"),
"act_mgr" : [
{
"sales" : {
"agent" : [
"rohan#walkover.in",
"abc#walkover.in"
],
"last_interacted" : "abc#walkover.in"
}
},
{
"developer" : {
"agent" : [
"newdeveloper#walkover.in"
],
"last_interacted" : "newdeveloper#walkover.in"
}
}
],
"email" : "aman#asasas.com",
"name" : "Aman",
"sales" : [
{
"sno" : 1,
"message" : "description",
"status" : "open"
},
{
"sno" : 12,
"message" : "assad",
"status" : "open"
}
]
}
>
The documentation on the $push and $set modifiers may be found in the "Updating" documentation:
http://www.mongodb.org/display/DOCS/Updating
More information on creating and updating embedded documents with Mongo db may be found in the documentation titled "Dot Notation (Reaching into Objects)"
http://www.mongodb.org/display/DOCS/Dot+Notation+%28Reaching+into+Objects%29
Information on updating embedded documents using the "$" positional operator may be found in the "The $ positional operator" section of the "Updating" documentation.
http://www.mongodb.org/display/DOCS/Updating#Updating-The%24positionaloperator
A word of caution: It is generally more common to have embedded documents all match the same structure, so that individual embedded documents may be referenced more easily. Your "sales" array is a good example of this; each embedded document contains the same keys, "sno", "message", and"status"
However, the embedded documents inside your "act_mgr" array contain different keys; the first contains "sales", and the second contains "developer". Instead, maybe consider the following structure:
"act_mgr" : [
{
"title" : "sales",
"agent" : [
"rohan#walkover.in",
"abc#walkover.in"
],
"last_interacted" : "abc#walkover.in"
},
{
"title": "developer",
"agent" : [
"newdeveloper#walkover.in"
],
"last_interacted" : "newdeveloper#walkover.in"
}
]
Now, each embedded documents contain the same keys, "title", "agent", and "last_interacted".
You could update sub-documents with the following command.
> db.sales.update({"act_mgr.title":"sales"}, {$push:{"act_mgr.$.agent":"abc#walkover.in"}, $set:{"act_mgr.$.last_interacted":"abc#walkover.in"}})
Hopefully this will allow you to make the updates that you need to, and perhaps give you some food for thought regarding schema design. Good luck!
Related
Use case : Posts filter items.
Summary : Posts will be filter by tags and category wise.
In this case i am returning filter items via a endpoint. The response are following.
Issue : Android/iOS developer are disagree with this response. Because of if i return KEY(tags/categories) wise response they
need to create 2 extra CLASS and that is cost with static binding. Also for future if i add another filter item like(rating-wise) they need to do again.
My response :
{
"status" : true,
"code" : 200,
"data" : {
"tags" : {
"filterTitle" : "Search By TAGS",
"lists" : [
{
"tagId" : 1,
"tagName" : "AWS"
},
{
"tagId" : 2,
"tagName" : "PHP"
},
{
"tagId" : 3,
"tagName" : "ASP"
}
]
},
"categories" : {
"filterTitle" : "Search By Category",
"lists" : [
{
"catId" : 10,
"catName" : "Web Services"
},
{
"catId" : 20,
"catName" : "Programming"
},
{
"catId" : 30,
"catName" : "Tools"
}
]
}
},
"message" : "successfull"
}
Android/iOS developer required :
{
"status" : true,
"code" : 200,
"data" : [
{
"filterTitle" : "Search By TAGS",
"lists" : [
{
"tagId" : 1,
"tagName" : "AWS"
},
{
"tagId" : 2,
"tagName" : "PHP"
},
{
"tagId" : 3,
"tagName" : "ASP"
}
]
},
{
"filterTitle" : "Search By Category",
"lists" : [
{
"catId" : 10,
"catName" : "Web Services"
},
{
"catId" : 20,
"catName" : "Programming"
},
{
"catId" : 30,
"catName" : "Tools"
}
]
}
],
"message" : "successfull"
}
Why not design the API to do the filtering. I know that data is not too much so you won't want to do it, but if that's the case any of the above implementation is fine, and yes they are correct they will need extra classes for each new filter type.
I run two MongoDB queries from PHP, one on a first collection (named "products"), second on another collection (named stats).
Some datas of the two collections :
{
"_id" : "20711122",
"labels_hierarchy" : [
"en:pgi"
],
"languages_hierarchy" : [
"en:french"
],
"labels_prev_hierarchy" : [
"en:pgi"
],
"languages" : {
"en:french" : 5
},
"countries_tags" : [
"en:france"
],
"purchase_places_debug_tags" : [],
"photographers_tags" : [
"tacite"
]
}
Other collection :
{
"_id" : "7613035010550",
"purchases" : [
{
"date" : ISODate("2017-04-15T14:15:00.000Z"),
"coords" : {
"lon" : 43.729604,
"lat" : 1.416017
},
"metar" : {},
"quantity" : 1,
"price" : 2.31
},
{
"date" : ISODate("2017-05-02T16:23:00.000Z"),
"coords" : {
"lon" : 43.722862,
"lat" : 1.415837
},
"metar" : {},
"quantity" : 6,
"price" : 12
},
{
"date" : ISODate("2017-05-02T18:32:00.000Z"),
"coords" : {
"lon" : 46.307353,
"lat" : 3.28937
},
"metar" : {},
"quantity" : 2,
"price" : 5
}
],
"rates" : [
{
"value" : 5
},
{
"value" : 4
},
{
"value" : 5
},
{
"value" : 2
}
]
}
As u see, collections are different but the "_id" key...
When i run a query on the first collection (products), everything is ok, but the second with the same "_key" returns empty results, here's the trace of the two queries (made with executeQuery() of MongoDB::Driver) :
<pre><code>Interrogation de la collection : stats
Avec le filtre :
{"id":"7613035010550"}
<pre><code>Interrogation de la collection : products
Avec le filtre :
{"id":"7613035010550"}
Results :
{"ean":"7613035010550","title":"Eau Min\u00e9rale Naturelle","image":"https:\/\/static.openfoodfacts.org\/images\/products\/761\/303\/501\/0550\/front_fr.11.400.jpg","brands":"Vittel","categories":["Boissons","Eaux","Eaux min\u00e9rales","Eaux min\u00e9rales naturelles","Boissons non sucr\u00e9es"],"quantity":"1.5 l."}
As u can see, only the first query returns results, not the second...
Any idea of this curious behaviour ?
Thx 4 help,
JL
I'm just stupid or tired...
Second query was execute with "id" key but not "_id" key... So, always returns empty results...
Just take another 4 shots coffee and next...
JL
I have this problem. I have this dataBase in mongoDB:
{
"_id" : ObjectId("585fe33d3c63b4a81e00002b"),
"class" : [
{
"name" : "class 1",
"people" : [
{
"id" : "58596",
"name" : "mark",
},
{
"id" : "45643",
"name" : "Susan",
},
{
"id" : "85952",
"name" : "Loris",
}
},
{
"name" : "class 2",
"people" : [
{
"id" : "58456",
"name" : "Sissi",
},
{
"id" : "45643",
"name" : "Susan",
}
]
}
]
}
I use php and I would like to know the names of the class with a specific name inside and save them in an array.
For example if I choose Susan i would like to have an array with ["class 1" , ["class 2"].
I have used findOne but this time i need to use find.
You can make use of MongoDB aggregation framework.
Here is a query which will give you the date in the desired form. However, I believe that there will be some better and efficient way to handle this but this is what I came up with.
db.collection.aggregate([
{"$unwind":"$class"},
{"$unwind":"$class.people"},
{"$match": {
"class.people.name":"Susan"
}
},
{"$group":{
"_id":"$class.people.name",
"classes":{"$push":"$class.name"}
}
}
])
Result :-
{ "_id" : "Susan", "classes" : [ "class 1", "class 2" ] }
Try to $match before first $unwind operation to avoid the unnecessary results in the pipeline before $unwind.
Refer Aggregation Pipeline Optimization for improved performance.
So my collection looks like this:
{
"_id" : ObjectId("52722429d874590c15000029"),
"name" : "Bags",
"products" : [{
"_id" : ObjectId("527225b5d87459b802000029"),
"name" : "Prada",
"description" : "Prada Bag",
"points" : "234",
"validDate" : 1382562000,
"link" : "dasdad",
"code" : "423423424",
"image" : null
}, {
"_id" : ObjectId("5272307ad87459401a00002a"),
"name" : "Gucci",
"description" : "Gucii bag",
"points" : "2342",
"validDate" : 1383170400,
"link" : "dsadada",
"code" : "2342",
"image" : null
}]
}
and I want to get only the product with the _id 527225b5d87459b802000029, I tried this:
$this->find(array(
'_id' => new \MongoId('52722429d874590c15000029'),
'products._id' => new \MongoId('527225b5d87459b802000029')
));
But it returns the entire array for that collection, and I only want one...can this be done in mongo?
As mentioned in comments, you have to add a projection, and more precisely an $elemMatch. No need to use the aggregation framework in that case.
Example :
find( { _id: 1, "products._id": 4 }, { products: { $elemMatch: { _id: 4 } } } ).pretty()
How to search value in multidimensional array,
for example I want to search example keyword in the following data in mongodb
I used to fetch all data from command
>db.info.find()
{
"_id" : ObjectId("4f74737cc3a51043d26f4b90"),
"id" : "12345",
"info" : [
{
"sno" : 1,
"name" : "ABC",
"email" : "abc#example.com"
},
{
"sno" : 2,
"name" : "XYZ",
"email" : "xyz#example.com"
},
{
"sno" : 3,
"name" : "XYZ",
"email" : "xyz#demo.com"
},
{
"sno" : 4,
"name" : "ABC",
"email" : "abc#demo.com"
},
{
"sno" : 5,
"name" : "Rohan",
"email" : "rohan#example.com"
}
]
}
Now, to find data having example I used command
>db.info.find({"info.email":"example"})
and it gives
{
"_id" : ObjectId("4f74737cc3a51043d26f4b90"),
"id" : "12345",
"info" : [
{
"sno" : 1,
"name" : "ABC",
"email" : "abc#example.com"
},
{
"sno" : 2,
"name" : "XYZ",
"email" : "xyz#example.com"
},
{
"sno" : 3,
"name" : "XYZ",
"email" : "xyz#demo.com"
},
{
"sno" : 4,
"name" : "ABC",
"email" : "abc#demo.com"
},
{
"sno" : 5,
"name" : "Rohan",
"email" : "rohan#example.com"
}
]
}
But I want only 3 out of 5 sub rows like
{
"_id" : ObjectId("4f74737cc3a51043d26f4b90"),
"id" : "12345",
"info" : [
{
"sno" : 1,
"name" : "ABC",
"email" : "abc#example.com"
},
{
"sno" : 2,
"name" : "XYZ",
"email" : "xyz#example.com"
},
{
"sno" : 5,
"name" : "Rohan",
"email" : "rohan#example.com"
}
]
}
Rohan, MongoDB always returns the whole document that you are searching on. You can't just make it return the array elements in which your keyword was found. If you want to do that, then you need to make sure all all embedded documents in the "info" field are in their own collection. And that might mean that you need to link them back to the original document in your "info" collection. Perhaps something like:
{
"sno" : 1,
"name" : "ABC",
"email" : "abc#example.com"
"info_id" : "12345",
},
Alternatively, you can of course do post-processing in PHP to obtain only the rows that you want.
Perhaps this is a good idea?
http://php.net/manual/en/class.mongoregex.php
I tried Map Reduce Function and it works on this type of problems the code is something like that:
Write a map function
map=function ()
{
filter = [];
this.info.forEach(function (s) {if (/example/.test(s.email)) {filter.push(s);}});
emit(this._id, {info:filter});
}
Write a reduce function
reduce=function(key, values) { return values;}
MapReduce Function
res=db.info.mapReduce(map,reduce,{out:{inline:1}})
And The Output look likes:
"results" : [
{
"_id" : ObjectId("4f9a2de0ea4a65c3ab85a9d3"),
"value" : {
"info" : [
{
"sno" : 1,
"name" : "ABC",
"email" : "abc#example.com"
},
{
"sno" : 2,
"name" : "XYZ",
"email" : "xyz#example.com"
},
{
"sno" : 5,
"name" : "Rohan",
"email" : "rohan#example.com"
}
]
}
}
],
"timeMillis" : 1,
"counts" : {
"input" : 3,
"emit" : 3,
"reduce" : 0,
"output" : 3
},
"ok" : 1,
Now you can find your search data from
printjson(res.results)
Did you try $ (projection)?
db.info.find({"info.email":"example"}, {"info.email.$":1})
document