How to update an array element in a MongoDB document - php

I've got a problem updating an array element in MongoDB. This is the structure of a document:
{
"_id" : ObjectId("57e2645e11c979157400046e"),
"site" : "BLABLA",
"timestamp_hour" : 1473343200,
"values" : [
{
"1473343200" : 66
},
{
"1473344100" : 230
},
{
"1473345000" : 479
},
{
"1473345900" : 139
}
]
}
Now I want to update the element with key "1473345900". How can I do this? I've tried:
db.COLLECTIONNAME.update({"values.1473345900": {$exists:true}}, {$set: {"values.$": 0}})
But after that the document looks like:
{
"_id" : ObjectId("57e2645e11c979157400046e"),
"site" : "BLABLA",
"timestamp_hour" : 1473343200,
"values" : [
{
"1473343200" : 66
},
{
"1473344100" : 230
},
{
"1473345000" : 479
},
0
]
}
What I'm doing wrong? I only want to update the value of 1473345900 to any value... I don't want to update the complete element...
Thanks a lot!!!

You need to add an additional query in your update that matches the array element you want to update. A typical query would involve checking for the element's value not equal to the one being updated.
The following example update shows this where the $ positional operator identifies the correct index position of the hash key array element { "1473345900": 139 }. If you try to run the update operation without the $ positional operator:
db.COLLECTIONNAME.update(
{ "values.1473345900": { "$exists": true } },
{ "$set": { "values.1473345900": 0 } }
)
mongo will treat the timestamp 1473345900 as the index position and thus you will get the error
can't backfill array to larger than 1500000 elements
Thus the correct way should be:
var val = 32;
db.COLLECTIONNAME.update(
{ "values.1473345900": { "$ne": val, "$exists": true } },
{ "$set": { "values.$.1473345900": val } }
)

Related

Is it possible to create relationship with data in array Laravel + MongoDB

I have a collection with Data1 like
{
_id : "1",
total_amount : 5876,
date: "20-Jun-2018"
},
{
_id : "2",
total_amount : 5776,
date: "20-Jun-2018"
}
I want to store these data in another collection Data2 as follows :
{
name : "XYZ",
adjustments : [
{
data1_id : "1",
adjust_amount : 675
},
{
data1_id : "2",
adjust_amount : 6785
}
]
}
Storing this data isn't a problem in an array of Objects form. But is there any way I can create a relationship with the data within the array adjustments?
At the time of listing, I want adjustments with adjust_amount and all the related data.

MongoDB find() in multidimensional array and $unset [duplicate]

Here is array structure
contact: {
phone: [
{
number: "+1786543589455",
place: "New Jersey",
createdAt: ""
}
{
number: "+1986543589455",
place: "Houston",
createdAt: ""
}
]
}
Here I only know the mongo id(_id) and phone number(+1786543589455) and I need to remove that whole corresponding array element from document. i.e zero indexed element in phone array is matched with phone number and need to remove the corresponding array element.
contact: {
phone: [
{
number: "+1986543589455",
place: "Houston",
createdAt: ""
}
]
}
I tried with following update method
collection.update(
{ _id: id, 'contact.phone': '+1786543589455' },
{ $unset: { 'contact.phone.$.number': '+1786543589455'} }
);
But it removes number: +1786543589455 from inner array object, not zero indexed element in phone array. Tried with pull also without a success.
How to remove the array element in mongodb?
Try the following query:
collection.update(
{ _id: id },
{ $pull: { 'contact.phone': { number: '+1786543589455' } } }
);
It will find document with the given _id and remove the phone +1786543589455 from its contact.phone array.
You can use $unset to unset the value in the array (set it to null), but not to remove it completely.
You can simply use $pull to remove a sub-document.
The $pull operator removes from an existing array all instances of a value or values that match a specified condition.
Collection.update({
_id: parentDocumentId
}, {
$pull: {
subDocument: {
_id: SubDocumentId
}
}
});
This will find your parent document against given ID and then will remove the element from subDocument which matched the given criteria.
Read more about pull here.
In Mongoose:
from the document:
To remove a document from a subdocument array we may pass an object
with a matching _id.
contact.phone.pull({ _id: itemId }) // remove
contact.phone.pull(itemId); // this also works
See Leonid Beschastny's answer for the correct answer.
To remove all array elements irrespective of any given id, use this:
collection.update(
{ },
{ $pull: { 'contact.phone': { number: '+1786543589455' } } }
);
To remove all matching array elements from a specific document:
collection.update(
{ _id: id },
{ $pull: { 'contact.phone': { number: '+1786543589455' } } }
);
To remove all matching array elements from all documents:
collection.updateMany(
{ },
{ $pull: { 'contact.phone': { number: '+1786543589455' } } }
);
Given the following document in the profiles collection:
{ _id: 1, votes: [ 3, 5, 6, 7, 7, 8 ] }
The following operation will remove all items from the votes array that are greater than or equal to ($gte) 6:
db.profiles.update( { _id: 1 }, { $pull: { votes: { $gte: 6 } } } )
After the update operation, the document only has values less than 6:
{ _id: 1, votes: [ 3, 5 ] }
If you multiple items the same value, you should use $pullAll instead of $pull.
In the question having a multiple contact numbers the same use this:
collection.update(
{ _id: id },
{ $pullAll: { 'contact.phone': { number: '+1786543589455' } } }
);
it will delete every item that matches that number. in contact phone
Try reading the manual.

MongoDB save and update array element

I have this current value that I've saved
db.mycol.save({name:'elbren',lastname:'antonio',subjects:{}})
result:
"_id" : ObjectId("576db356332a8fc87bf769be"),
"name" : "elbren",
"lastname" : "antonio",
"subjects" : {
}
What I need is this result:
"_id" : ObjectId("576db356332a8fc87bf769be"),
"name" : "elbren",
"lastname" : "antonio",
"subjects" :
{
{
code: "sub1",
Description: "desc1",
Unit: 3
},
code: "sub2",
Description: "desc2",
Unit: 3
}
What is the best thing to do on this which is I want to add subjects into that _id?
To create the document so that you get the desirable result, just write it directly:
db.mycol.save({name:'elbren',lastname:'antonio',subjects:{
{
code: "sub1",
Description: "desc1",
Unit: 3
},
code: "sub2",
Description: "desc2",
Unit: 3
}})
If you want to change ("fix") the existing document, you have to use update:
db.mycol.update(
{ name : "elbren", lastname : "antonio" },
{ $set: { subjects:{
{
code: "sub1",
Description: "desc1",
Unit: 3
},
code: "sub2",
Description: "desc2",
Unit: 3
}
}}
);
Here { name : "elbren", lastname : "antonio" } is a query that matches the document you want, and the second part is the update parameter.
Use "$push" operator to add array to current object.
// in php e.g:
['$push'=>['fild_value'=>array('mail=>'me#mail.com','tag'=>'personal')]]
More result this:
{
"_id": 12345678,
"fild_value": [
{
"mail":"me#mail.com",
"tag":"personal"
},
{
"mail":"job#mail.com",
"tag":"worker"
}
]
}
MongoDB provide array operators ($push/$pull,$addToSet,$elemMatch,etc...)

MongoDB PHP (SUM)?

as mysql query: select sum(adet) from stok where isbn=$isbn. I want to make this query as a mongodb query but I couldn't make. I've read some code examples but I didn't understand how it works.
I need some help.
MongoDB's query language doesn't give us the ability to perform summations, but we can utilize its aggregation framework to do so.
Given the following sample data:
> db.stok.insert({ isbn:"foo", adet: 5 })
> db.stok.insert({ isbn:"foo", adet: 3 })
> db.stok.insert({ isbn:"foo", adet: 1 })
> db.stok.insert({ isbn:"bar", adet: 2 })
> db.stok.insert({ isbn:"bar", adet: 4 })
> db.stok.find()
{ "_id" : ObjectId("51cde94037a16345b5316987"), "isbn" : "foo", "adet" : 5 }
{ "_id" : ObjectId("51cde94437a16345b5316988"), "isbn" : "foo", "adet" : 3 }
{ "_id" : ObjectId("51cde94b37a16345b5316989"), "isbn" : "foo", "adet" : 1 }
{ "_id" : ObjectId("51cde95337a16345b531698a"), "isbn" : "bar", "adet" : 2 }
{ "_id" : ObjectId("51cde95637a16345b531698b"), "isbn" : "bar", "adet" : 4 }
We could summate all of the adet values for "foo" isbn values with the following pipeline (i.e. sequence of aggregation operators):
> db.stok.aggregate(
... { $match: { isbn: "foo"}},
... { $group: { _id: 1, sum: { $sum: "$adet" }}}
... );
{ "result" : [ { "_id" : 1, "sum" : 9 } ], "ok" : 1 }
Here, we're narrowing the considered documents by the isbn field with $match, and then using $group to collect all of those into a single bucket and aggregate the adet field with a summation.
We could also compute sums for each distinct isbn value by using a non-constant _id in our grouping:
> db.stok.aggregate({ $group: { _id: "$isbn", sum: { $sum: "$adet" }}});
{
"result" : [
{
"_id" : "bar",
"sum" : 6
},
{
"_id" : "foo",
"sum" : 9
}
],
"ok" : 1
}
The above examples use the JS shell, but you can execute aggregation queries in PHP with either the MongoCollection::aggregate() helper method, or by directly invoking the aggregate command with MongoDB::command().

MongoDB Query to find out all the array elements of a collection

I have a pretty big MongoDB document that holds all kinds of data. I need to identify the fields that are of type array in a collection so I can remove them from the displayed fields in the grid that I will populate.
My method now consists of retrieving all the field names in the collection with
This was taken from the response posted here MongoDB Get names of all keys in collection
mr = db.runCommand({
"mapreduce" : "Product",
"map" : function() {
for (var key in this) { emit(key, null); }
},
"reduce" : function(key, stuff) { return null; },
"out": "things" + "_keys"
})
db[mr.result].distinct("_id")
And running for each of the fields a query like this one
db.Product.find( { $where : "Array.isArray(this.Orders)" } ).count()
If there's anything retrieved the field is considered an array.
I don't like that I need to run n+2 queries ( n being the number of different fields in my collection ) and I wouldn't like to hardcode the fields in the model. It would defeat the whole purpose of using MongoDB.
Is there a better method of doing this ?
I made a couple of slight modifications to the code you provided above:
mr = db.runCommand({
"mapreduce" : "Product",
"map" : function() {
for (var key in this) {
if (Array.isArray(this[key])) {
emit(key, 1);
} else {
emit(key, 0);
}
}
},
"reduce" : function(key, stuff) { return Array.sum(stuff); },
"out": "Product" + "_keys"
})
Now, the mapper will emit a 1 for keys that contain arrays, and a 0 for any that do not. The reducer will sum these up, so that when you check your end result:
db[mr.result].find()
You will see your field names with the number of documents in which they contain Array values (and a 0 for any that are never arrays).
So this should give you which fields contain Array types with just the map-reduce job.
--
Just to see it with some data:
db.Product.insert({"a":[1,2,3], "c":[1,2]})
db.Product.insert({"a":1, "b":2})
db.Product.insert({"a":1, "c":[2,3]})
(now run the "mr =" code above)
db[mr.result].find()
{ "_id" : "_id", "value" : 0 }
{ "_id" : "a", "value" : 1 }
{ "_id" : "b", "value" : 0 }
{ "_id" : "c", "value" : 2 }

Categories