remove element from embedded document in mongodb - mongodb

I am using mongodb library for codeigniter.i want to delete element from embedded document. my collection is as follows-
{
"_id" : ObjectId("56503a272f170d30298b45ad"),
"gm_creation_time" : "2015-11-21 09:32:23",
"gm_favourites" : [
{
"gm_user_id" : "55f90ccf2f170d79048b4570",
"gm_id" : "56503a272f170d30298b45ad",
"date" : "2015-11-21 09:32:40"
}
],
"gm_members" : [
"560391de2f170d1e108b4574",
"55f90ccf2f170d79048b4570"
],
"gm_name" : "Sunny#ccs",
"gm_owner" : "55f90ccf2f170d79048b4570",
"gm_photo" : null,
"gm_posts" : [ ],
"gm_type" : "1",
"gm_updation_time" : "2015-11-21 09:32:40"
}
How can I delete from favorites according to gm_user_id. I am new to codeigniter+mongodb. please help

Use the $pull array modifier operator to remove all instances of a value or values that match a specified condition from an existing array.
The following mongo operation updates all documents in the collection to remove the object with "gm_user_id" property that has a value of "55f90ccf2f170d79048b4570" from the array gm_favourites:
db.collection.update(
{ },
{
"$pull": {
"gm_favourites": {
"gm_user_id": "55f90ccf2f170d79048b4570"
}
}
},
{ "multi": true }
);
This will translate to PHP as follows:
$connection = new Mongo();
$db = $connection->selectDB('dbname');
$collection = $db->selectCollection('collection_name');
$filter = array();
$remove_document = array(
'$pull' => array(
'gm_favourites' => array(
'gm_user_id' => '55f90ccf2f170d79048b4570',
)
)
);
$options['multiple'] = true;
$collection->update($filter, $remove_document, $options);

If you want to remove the embedded document based on gm_user_id use the following command. (Assuming the collection name is favorites):
db.test.update( {} , {$pull:{'gm_favourites':{'gm_user_id' : '55f90ccf2f170d79048b4570'}}})
The above command will remove the matching embedded document.

Related

How to project specific fields from a document inside an array?

here is a typical document
{
title : 'someTitle',
places : [{name : 'someName', location : 'someLocation'}, {name ...}]
}
I have the following query
var qs = {title : 'someTitle', places : {$elemMatch : {name : 'someName' } } };
where I select a document which matches the title and which contains a document entry within its 'places' array that has name equal to 'someName'. However the issue is that the entries within the places array are large documents, and I only need a couple of fields from that document. I tried projecting the fields like so but it did not work.
var projection = {'places.$.name': 1, 'places.$.location' : 1};
Which is supposed to return an array with a document containing only the 'name' and 'location' property.
I got the following error
Can't canonicalize query: BadValue Cannot specify more than one positional proj. per query.
to be clear, I would like to accomplish this without the aggregate framework
You are doing it wrong. According to the documentation
Only one positional $ operator may appear in the projection document.
But you still need to use the $ operator to get the expected result:
var qs = { title : 'someTitle', 'places.name' : 'someName' };
var projection = {'places.$': 1 };
db.collection.find(qs, projection);
Which returns:
{
"_id" : ObjectId("564f52d7d9a433df958b5630"),
"places" : [
{
"name" : "someName",
"location" : "someLocation"
}
]
}
Also you don't need the $elemMatch operator here use "dot notation" instead.
Now if what you want is an array of "name" and "location" for each subdocument in the array then aggregation is the way to go.
db.collection.aggregate([
{ '$match': {
'title' : 'someTitle',
'places.name' : 'someName'
}},
{ '$project': {
'places': {
'$map': {
'input': '$places',
'as': 'place',
'in': {
'name': '$$place.name',
'location': '$$place.location'
}
}
}
}}
])
Which yields:
{
"_id" : ObjectId("564f52d7d9a433df958b5630"),
"places" : [
{
"name" : "someName",
"location" : "someLocation"
},
{
"name" : "bar",
"location" : "foo"
}
]
}
For the fields inside an array, you can project them the same as in embedded object
var projection = {'places.name': 1, 'places.location' : 1};
Check this guideline
https://docs.mongodb.com/manual/reference/operator/aggregation/project/#include-specific-fields-from-embedded-documents

Script to add one value to array in mongo collection

/* 0 */
{
"_id" : ObjectId("55addc2f8dab32aca87ce0bd"),
"partNum" : "part1",
"dest" : "First Part",
"sales" : [
"sale1",
"sale2",
"sale3"
],
"salesData" : {
"sale1" : {
"mcode" : "mc11",
"dtype" : [
"AAA",
"BBB"
]
}
}
}
/* 1 */
{
"_id" : ObjectId("55addc408dab32aca87ce0be"),
"partNum" : "part2",
"dest" : "Second Part",
"sales" : [
"sale1",
"sale2",
"sale3"
],
"salesData" : {
"sale1" : {
"mcode" : "mc22",
"dtype" : [
"AAA",
"BBB"
]
}
}
}
I am not that much efficient in writing mongo script. My requirement is to append one more value to "dtype" array wherever "mcode" is "mc11" in all of the documents inside the collection. Above is the two document output from my collection. I was using the below script to do it and its not working. Can anyone please help me
db.testingRD.find().forEach( function(myDocument)
{
db.testingRD.update({id: myDocument._id}, {$push : {"salesData.sale1.dtype" : "DDD"}});
});
To append one more value to "dtype" array wherever "mcode" is "mc11", use the following update where the query object is the selection criteria for the update and is the same query selector as in the find() method, the update object has the $push modifications to apply and then the options document which is optional. If that is set to true, it updates multiple documents that meet the query criteria:
var query = { "salesData.sale1.mcode": "mc11" },
update = {
"$push": { "salesData.sale1.dtype": "DDD" }
},
options = { "multi": true };
db.testingRD.update(query, update, options);
You had a typing mistake in the script (you forgot an underscore):
db.testingRD.find().forEach( function(myDocument)
{
db.testingRD.update({_id: myDocument._id}, {$push : {"salesData.sale1.dtype" : "DDD"}});
});
I always use a trick when an update seams to not working: I change the update with a printjson + find so that I can see if it is matching anything:
db.testingRD.find().forEach( function(myDocument) { printjson(db.testingRD.find({_id: myDocument._id})) } );

add new and update existing document in embedded array

Is there a way to add or remove documents from an embedded array, and update existing documents
in an embedded array?
e.g. Given
{
"_id" : ObjectId("547dd21f6e04d152fccedf1b"),
"intF" : 0,
"arrayD" : [
{
"name" : "baz",
"contents" : "baz contents"
}
}
trying
db.dummy.update(
// query
{
"_id" : ObjectId("547dd21f6e04d152fccedf1b")
},
// update
{
$set : { "arrayD.0.contents": "no contents" },
$push : { arrayD : { $each : [ { name : "bam", contents : null } ] }
}
},
// options
{
"multi" : false, // update only one document
"upsert" : false // insert a new document, if no existing document match the query
}
);
gives error
Cannot update 'arrayD.0.contents' and 'arrayD' at the same time
The options I see are
Use $set and write whole array
Use multiple updates, one for $set to modify existing entries, one for $push/$pull to add/remove entries.
is there a better way?

Mongodb update subdocument inside array field of a collection

I have a mongodb collection like
{
"_id" : ObjectId("5375ef2153bb790b20d8a660"),
"association" : [
{
"count" : 3,
"name" : "hayatdediğin"
},
{
"count" : 2,
"name" : "sadecesenolsan"
},
{
"count" : 2,
"name" : "üslupnamustur"
}
],
"tag_count" : 4,
"tag_name" : "vazgeçilmezolan",
"variation" : [
{
"count" : 4,
"name" : "VazgeçilmezOlan"
}
]
}
Each collection consists of tag_name, tag_count, array field association and array field variation. For each name inside association, there exists a different document same as this document. I need to add new field "total_count" inside each association dictionary whose value equals the tag_count of the name by querying the database.
I tried this code but its not working
db.hashtag.find().forEach(function (doc) {
if (doc.association.length != 0 ) {
doc.association.forEach(function (assoc) {
db.hashtag.find({'tag_name': assoc.name}).forEach(function(tag){
assoc.total_count=tag.tag_count;
})
});
}
});
After modifying each doc you need to call save on the collection to commit the change.
Assuming you're doing this in the shell:
db.hashtag.find().forEach(function (doc) {
if (doc.association.length != 0 ) {
doc.association.forEach(function (assoc) {
db.hashtag.find({'tag_name': assoc.name}).forEach(function(tag){
assoc.total_count=tag.tag_count;
});
});
// Save the changed doc back to the collection
db.hashtag.save(doc);
}
});
To update doc in database you have to use db.hashtag.update, not db.hashtag.find. Find only retrieves document from db.
I changed the previous method of looping using forEach and then saved the doc at last and the code worked.
db.hashtag.find().forEach(function (doc) {
var array = doc.association;
if (array != undefined){
for(var i=0;i<array.length;i++)
{
var obj = db.hashtag.findOne({'name':array[i].name});
var count = obj.count;
doc.association[i].total_count = count;
db.hashtag.save(doc);
}
}
});

how to update whole object in mongodb?

In the document below, I have an array called imAccounts. I want to update() the object in that array. How can I do that?
{
"_id" : ObjectId("503c55da1c192a530b000001"),
"imAccounts" : [
{
"accountType" : "Windows",
"accountName" : "rwqerqw",
"accountPassword" : "erqwerwe"
},
{
"accountType" : "Yahoo",
"accountName" : "rwqerqw",
"accountPassword" : "erqwerwe"
}]
}
With this document structure you can update an object in the array using the positional operator ($):
db.myarray.update(
{ // Match criteria
"_id" : ObjectId("503c55da1c192a530b000001"),
'imAccounts.accountType': 'Yahoo',
},
{ // Update first matched item using positional operator $
'$set' : { 'imAccounts.$.password':'sekrit'}
}
)
Note that the positional operator currently only applies to the first matched item in the query.