mongodb: remove subdocument with where clause that includes document & subdocument - mongodb

Here is my collection (workers):
"type" : "Manager",
"employees" : [{
"name" : "bob"
"id" : 101
},{
"name" : "phil"
"id" : 102
},{
"name" : "bob"
"id" : 103
}]
First: this is NOT an array so $pullAll will not work or other array commands. All I want to do is: (1) search the collection for id 101 in ALL subdocuments with type Manager. (2) If 101 exists in a "Manager" subdocument, I want to remove item 103.
I have been pouring over the interwebs for two days on this issue and cannot figure it out.
I've tried this (and many other variations):
db.workers.update( {"type":"Manager","employees.id":101},{$pull : {"employees.id" : {"id" : 103}}},false,true)

The syntax of your $pull object is off. Try this instead:
db.workers.update({"type":"Manager","employees.id":101},
{$pull : {"employees" : {"id" : 103}}},false,true)
To confirm they were removed:
db.workers.find({
type: "Manager",
$and: [{'employees.id': 101}, {'employees.id': 103}]
})

Related

removing an object from a mongodb document

I have a document in Mongodb collection, where I want to remove an object, using title key.
I tried using $unset, but it only removes the title key not the object to which it belongs.
{
"_id" : ObjectId("576b63d49d20504c1360f688"),
"books" : [
{
"art_id" : ObjectId("574e68e5ac9fbac82489b689"),
"title" :"abc",
"price" : 40
},
{
"art_id" : ObjectId("575f9badada0500d192c53f4"),
"title" : "xyz",
"price" : 20
},
{
"art_id" : ObjectId("57458224d86b3d1561150f17"),
"title" : "def",,
"price" : 30
}
],
"user_id" : "575570c315e27d13167dfc0d"
}
To remove the entire object that contains the query object use db.remove() query.
For your case:
db.yourcollection.remove({"books.title": "abc"});
Please double check the format in which the element of array is referenced.
This removes the entire objects that contains the embedded query obj. To remove only a single object, provide it with another field to uniquely identify it.
If you only want to remove the object that contains the title field from the array but wants to keep the object that contains the array, then please use the $pull operator. This answer will be of help.
Example: if you want to remove object
{
"art_id" : ObjectId("574e68e5ac9fbac82489b689"),
"title" :"abc",
"price" : 40
}
just from the array but keep the parent object like
{
"_id" : ObjectId("576b63d49d20504c1360f688"),
"books" : [
{
"art_id" : ObjectId("575f9badada0500d192c53f4"),
"title" : "xyz",
"price" : 20
},
{
"art_id" : ObjectId("57458224d86b3d1561150f17"),
"title" : "def",,
"price" : 30
}
],
"user_id" : "575570c315e27d13167dfc0d"
}
use
db.mycollection.update(
{'_id': ObjectId("576b63d49d20504c1360f688")},
{ $pull: { "books" : { "title": "abc" } } },
false,
true
);
$unset won't remove the object from an array. The $unset operator deletes a particular field. doc.
Use $pull instead.
The $pull operator removes from an existing array all instances of a value or values that match a specified condition.
Try following query
db.collName.update({$pull : {books:{title:abc}}})
Refer $pull-doc
Hope this will help you.
And if... ¿Do I want to delete an object that is inside a document and not as an array?
{
"_id" : ObjectId("576b63d49d20504c1360f688"),
"books" : {
"574e68e5ac9fbac82489b689": {
"art_id" : ObjectId("574e68e5ac9fbac82489b689"),
"title" :"abc",
"price" : 40
},
"575f9badada0500d192c53f4": {
"art_id" : ObjectId("575f9badada0500d192c53f4"),
"title" :"xyz",
"price" : 20
},
"57458224d86b3d1561150f17": {
"art_id" : ObjectId("57458224d86b3d1561150f17"),
"title" : "def",
"price" : 30
}
},
"user_id" : "575570c315e27d13167dfc0d"
}
The solutions is this:
db.auctions.update(
{'_id': ObjectId("576b63d49d20504c1360f688")},
{$unset: {"books.574e68e5ac9fbac82489b689":
{_id: "574e68e5ac9fbac82489b689"}}})
Try using pull.
https://docs.mongodb.com/manual/reference/operator/update/pull/
$pull
The $pull operator removes from an existing array all instances of a value or values that match a specified condition.
The $pull operator has the form:
{ $pull: { <field1>: <value|condition>, <field2>: <value|condition>, ... } }
To specify a <field> in an embedded document or in an array, use dot notation.
Try in the mongo shell
db.yourcollection.remove({books:[{title:'title_you_want'}]})
Careful with the braces.

MongoDB count occurances of a substring in a collection

Hello I'm a MongoDb beginner. I have a database of a IRC chatlog. The document structure is very simple
{
"_id" : ObjectId("000"),
"user" : "username",
"message" : "foobar foobar potato idontknow",
"time" : NumberLong(1451775601469)
}
I have thousands of these and I want to count the number of occurrences of the string "foobar". I have googled this issue and found something about aggregations. I looks very complicated and I haven't really found any issue this "simple". I'd be glad if someone pointed me in the right direction what to research and I wouldn't mind an example command that does exactly this what I want. Thank you.
There is no any built-in operator to solve your request.
You can try this query, but it has very poor performance:
db.chat.find().forEach(function(doc){
print(doc["user"] + " > " + ((doc["message"].match(/foobar/g) || []).length))
})
If you could change your message field to array, then we could apply aggregation...
EDIT:
If you add array of splitted words into your entry, we can apply aggregation
Sample:
{
"_id" : ObjectId("569bb7040586bcb40f7d2539"),
"user" : "username",
"fullmessage" : "foobar foobar potato idontknow",
"message" : [
"foobar",
"foobar",
"potato",
"idontknow"
],
"time" : NumberLong(1451775601469)
}
Aggregation. We create new entry for each array element, match given word (foobar, in this case) and then count matched result.
db.chat.aggregate([
{"$unwind" : "$message"},
{"$match" : {"message" : {"$regex" : "foobar", "$options" : "i"}}},
{"$group" : {_id:{"_id" : "$_id", "user" : "$user", "time" : "$time", "fullmessage" : "$fullmessage"}, "count" : {$sum:1}}},
{"$project" : {_id:"$_id._id", "user" : "$_id.user", "time" : "$_id.time", "fullmessage" : "$_id.fullmessage", "count" : "$count"}}
])
Result:
[
{
"_id" : ObjectId("569bb7040586bcb40f7d2539"),
"count" : 2,
"user" : "username",
"time" : NumberLong(1451775601469),
"fullmessage" : "foobar foobar potato idontknow"
}
]

Mongo query with 'like' (regex); extract the field that provide the matching

I'm looking some way for extract the field that provide matching. Example from mongo shell:
db.estates.find({$or: [{street: /a/i}, {number: '64'}]}, {street: 1, number: 1})
{ "_id" : ObjectId("551f8b1efec981df83afbaee"), "number" : "123", "street" : "abcd" }
{ "_id" : ObjectId("551f8b36fec981df83afbb05"), "street" : "qwer", "number" : "64" }
I want to get in results some value pointing to field that provided the matching, or get only this field. Is it real?

Find oldest/youngest post in mongodb collection

I have a mongodb collection with many fields. One field is 'date_time', which is in an ISO datetime format, Ex: ISODate("2014-06-11T19:16:46Z"), and another field is 'name'.
Given a name, how do I find out the oldest/youngest post in the collection?
Ex: If there are two posts in the collection 'data' :
[{'name' : 'John', 'date_time' : ISODate("2014-06-11T19:16:46Z")},
{'name' : 'John', 'date_time' : ISODate("2015-06-11T19:16:46Z")}]
Given the name 'John' how do I find out the oldest post in the collection i.e., the one with ISODate("2014-06-11T19:16:46Z")? Similarly for the youngest post.
Oldest:
db.posts.find({ "name" : "John" }).sort({ "date_time" : 1 }).limit(1)
Newest:
db.posts.find({ "name" : "John" }).sort({ "date_time" : -1 }).limit(1)
Index on { "name" : 1, "date_time" : 1 } to make the queries efficient.
You could aggregate it as below:
Create an index on the name and date_time fields, so that the
$match and $sort stage operations may use it.
db.t.ensureIndex({"name":1,"date_time":1})
$match all the records for the desired name(s).
$sort by date_time in ascending order.
$group by the name field. Use the $first operator to get the first
record of the group, which will also be the oldest. Use the $last
operator to get the last record in the group, which will also be the
newest.
To get the entire record use the $$ROOT system variable.
Code:
db.t.aggregate([
{$match:{"name":"John"}},
{$sort:{"date_time":1}},
{$group:{"_id":"$name","oldest":{$first:"$$ROOT"},
"youngest":{$last:"$$ROOT"}}}
])
o/p:
{
"_id" : "John",
"oldest" : {
"_id" : ObjectId("54da62dc7f9ac597d99c182d"),
"name" : "John",
"date_time" : ISODate("2014-06-11T19:16:46Z")
},
"youngest" : {
"_id" : ObjectId("54da62dc7f9ac597d99c182e"),
"name" : "John",
"date_time" : ISODate("2015-06-11T19:16:46Z")
}
}
db.t.find().sort({ "date_time" : 1 }).limit(1).pretty()

mongodb replace all instances of certain value for subdocument

My collection (called "workers"):
"_id" : "500"
"type" : "Manager",
"employees" : [{
"name" : "bob"
"id" : 101
},{
"name" : "phil"
"id" : 102
}]
Goal: for every _id that is a type: Manager AND that contains a subdocument that has an "id" of 102: replace 102 with 202.
Desired End result:
"_id" : "500"
"type" : "Manager",
"employees" : [{
"name" : "bob"
"id" : 101
},{
"name" : "phil"
"id" : 202
}]
I have tried:
db.workers.update({type:'Manager','employees.id':'102'},{$set:{'employees.id':'202'}},{multi:true})
I then did the following two things to verify:
db.workers.find({type: "Manager", 'employees.id': 102}).count()
I get a result of 9.
I also tried this to verify:
db.workers.find({$and: [{type: "Manager"},{"employees.id":60}]}).count()
This returned 0.
I am pretty confused at this point. Is my update wrong? is my find wrong? Is it both? Is the '9' result wrong? Is the '0' wrong?
You need to use the $ positional update operator to update the specific element that matched your query. Your update is also using values of '102' and '202' which makes the update try and match strings when those fields are numbers.
Your update should look like this instead:
db.workers.update(
{type: 'Manager', 'employees.id': 102},
{$set: {'employees.$.id': 202}},
{multi: true})