MongoDB + Laravel + jenssegers/laravel-mongodb + update nested child elements - mongodb

Hellow folks, I am new to MongoDB and looking for some answer
Is there any way to update nested array without looping it.
foreach ($post->comments as $key => $comment) {
if ($comment['posted_by'] == $authUser['id']) {
$data = $post->update([
"comments.$key.description" => $dataArray['description'],
"comments.$key.updated_at" => $dataArray['updated_at'],
]);
}}
I want to to do something like below.
$post = Post::where('_id', $id)->where('comments.*.id', $commentId)->update(array('description' => $desc));
Or I have to write raw MongoDB query for that.
I have 1 level nested comment also under main comments so if I want to update nested comment than I have to loop comment array than the nested comment array.
if ($subCommentId) {
foreach ($comment as $nestedkey => $nestedComments) {
if ($nestedComments['id'] === $subCommentId && $nestedComments['posted_by'] == $authUser['id']) {
$data = $post->update([
"comments.$key.$nestedkey.description" => $dataArray['description'],
"comments.$key.$nestedkey.updated_at" => $dataArray['updated_at'],
]);
}
}
}
Something like this :
$post = Post::where('_id', $id)->where('comments.*.id', $commentId)->where('comments.*.*.id', $subCommentId)->update(array('description' => $desc));
Is it good to store comment in the same collection as an array or should I create a new collection for that as maximum BSON document size is 16 megabytes and how much comments it can store like 10K or more?
Below is my sample comment array format under one Collection.
"comments" : [
{
"description" : "description some",
"channel" : "swachhata-citizen-android",
"user_role" : "Citizen",
"id" : "5b4dc367d282f",
"user_role_id" : ObjectId("5accd7f8309a203be03b6441"),
"created_at" : "2018-07-17 15:52:31",
"updated_at" : "2018-07-17 15:52:31",
"ip_address" : "127.0.0.1",
"user_agent" : "PostmanRuntime/6.4.1",
"deleted" : false,
"channel_id" : "5acccfe4309a2038347a5c47",
"posted_by" : NumberInt(1),
"comments" : [
{
"description" : "some description nested",
"channel" : "swachhata-citizen-android",
"user_role" : "Citizen",
"id" : "5b4dcfc7022db",
"user_role_id" : ObjectId("5accd7f8309a203be03b6441"),
"created_at" : "2018-07-17 16:45:19",
"updated_at" : "2018-07-17 16:45:19",
"ip_address" : "127.0.0.1",
"user_agent" : "PostmanRuntime/6.4.1",
"deleted" : false,
"channel_id" : "5acccfe4309a2038347a5c47",
"posted_by" : NumberInt(1)
}
]
}
]
Thanks. :)

To update nested document, you should use arrayFilters:
Post::raw()->updateMany(
[],
[ '$set' => ["comments.$[i].comments.$[j].description" => $desc] ],
[ '$arrayFilters' => [
[
[ "i.id" => "5b4dc367d282f" ],
[ "j.id" => "5b4dcfc7022db" ]
]
]
]
)
Hope it helps :)

Related

MongoDB delete specific nested element in object array

I want to remove this
"lightControl" : 75
from this
{
"_id" : "dfdfwef-fdfd-fd94284o-aafg",
"name" : "Testing",
"serialNumber" : "fhidfhd8ghfd",
"description" : "",
"point" : {
"type" : "Point",
"coordinates" : [
10.875447277532754,
20.940549069378634
]
},
"ancestors" : [ ],
"metadata" : {
"measurement" : {
"high" : "40000.0",
"medium" : "25000.0"
},
"digitalTwin" : {
},
"emails" : [
""
],
"lastMeasurementDate" : "2010-03-04T11:32:06.691Z",
"lightControl" : 75
},
"tags" : [ ],
"createdAt" : ISODate("2019-12-07T15:22:10.988Z"),
"updatedAt" : ISODate("2020-03-08T15:38:21.736Z"),
"_class" : "com.test.demo.api.model.Device"
}
All I want is for this specific id, to completely delete the lightControl element from metadata. I have tried $pull, but I am probably missing something. Any ideas? Thank you in advance!
Your lightControl is not in array, for nested property, use the dot wrapped in doublequotes:
MongoDB shell:
db.getCollection('yourCollectionName').update({},{$unset:{
"metadata.lightControl":""
}})
In case you have a list of objects with _id(s) instead of updating directly, assume Node.js client for MongoDB is used:
// import mongodb from "mongodb"; // ES6
const mongodb = require("mongodb");
var client = MongoClient(...);
var coll = client["yourDbName"]["yourCollectionName"];
var objs = []; // <-- The array with _id(s)
for (let i=0; i<objs.length; i++){
let id = mongodb.ObjectID(objs[i]["_id"]);
coll.update({ _id:id },{$unset:{ "metadata.lightControl":"" }});
}

Python check MongoDB field exists or not

I have two collections one is websites which stores information like:
{
"_id" : ObjectId("5ac5efd6a37efa4c0e28f5aa"),
"main_id" : 3,
"status" : "",
"website" : "http://test.com",
"last_access_time" : "2018-04-16 17:49:03",
"links" : [
{
"link_id" : "test-1",
"link" : "test1.html"
},
{
"link_id" : "test-2",
"link" : "test.html"
}
]
}
And another is website_info in which I want store info like:
{
"_id" : ObjectId("5ad72ddecf45b60dffcbf9f2"),
"main_id" : 3,
"last_access_time" : "2018-04-18 15:37:02",
"test-1" : {
"no_of_links" : 55,
"links_2" : [
{
"link" : "/home",
"link_id" : "secnd-1",
},
{
"link" : "/login",
"link_id" : "secnd-2",
},
{
"link" : "/services",
"link_id" : "secnd-3",
}
]
},
"test-2" : {
"no_of_links" : 55,
"links_2" : [
{
"link" : "/home",
"link_id" : "secnd-1",
},
{
"link" : "/login",
"link_id" : "secnd-2",
},
{
"link" : "/services",
"link_id" : "secnd-3",
}
]
}
}
I am using Python3 and mongoDB.
Here I want to check the field like "link_id" which is "test-1" in the website_info for main_id = 3 exists or not. If it is exists I will update for same, if does not exists I want to insert new record set.
The thing is how to check whether field "test-1" (which is the value from websites collection) in website_info collection exists or not.
Help is appreciated.
Here in my case, link_id will be unique in website_info collection. So no need to check for main_id, only checking for link_id solved my issue, like:
#classmethod
def find_link(self, link_id):
cursor = self.db.collection.find({link_id: {'$exists': True}} )
results = list(cursor)
return results
And check for exists like:
if(len(is_exists)>0):
#do if exists

mongodb query find in array

I struggle with a find query.
I have two documents in a mongodb grid collection:
{
"_id" : ObjectId("55b8ac2c1a80142e7f7b23cd"),
"metadata" : {
"filename" : "test2.xml",
"contentType" : "application/xml"
},
"data" : {
"type_file" : "test",
"vision_id" : "6987"
},
"filename" : "test2.xml",
"uploadDate" : ISODate("2015-07-29T10:34:20.991Z"),
"length" : NumberLong(9582),
"chunkSize" : NumberLong(261120),
"md5" : "ea40283994f451b357555e53d186ed1e"
}
{
"_id" : ObjectId("55b8ac2c1a80142e7f7b23cd"),
"metadata" : {
"filename" : "test.xml",
"contentType" : "application/xml"
},
"data" : {
"type_file" : "test",
"vision_id" : "1282"
},
"filename" : "test.xml",
"uploadDate" : ISODate("2015-07-29T10:34:20.991Z"),
"length" : NumberLong(9582),
"chunkSize" : NumberLong(261120),
"md5" : "ea40283994f451b357555e53d186ed1e"
}
Now I want to make a query which retreive the document where "filename" = "test.xml" and the tag "vision_id" = "1282".
Now I made the search query like this:
$query =
array('$and' =>
array(
array("filename" => "text.xml),
array("data" => array("vision_id" => "1282")),
),
);
$cursor = $gridFS->find($query)
If I run this I don't get a result:
When I remove the line array("data" => array("vision_id" => "1282")), then I get the last document. (As I predicted).
Could anybody give me a push to the right way, to search also within the data array?
Kind Regards,
Arjan Kroon
I found the solution.
$query =
array('$and' =>
array(
array("filename" => "text.xml"),
array("data.vision_id" => "1282"),
),
);

MongoDB Aggregation: Value in Array

We have the following Testsnippet in Ruby
def self.course_overview(course_member=nil)
course_member = CourseMember.last if course_member == nil
group_global = {"$group" =>
{"_id" => { "course_id" => "$course_id",
"title" => "$title",
"place" => "$place",
"description" => "$description",
"choosen_id" => "$choosen_id",
"year" => {"$year" => "$created_at"},
"course_member_ids" => "$course_member_ids"}}
}
match_global = {"$match" => {"_id.course_member_ids" => {"$in" => "#{course_member.id}"} }}
test = CoursePlan.collection.aggregate([group_global, match_global])
return test
end
The problem is the "match_global" statement. We would like to match all Documents where the course_member ID is appearing in the course_member_ids array.
The above statement fails with the error: "...must be an array". This make sense to me but according to other comments on the web this should be possible this way.
Any advice? How is it possible to return the docs where the course_member id is in the array of the course_member ids?
Sample CoursePlan Object:
{
"_id" : ObjectId("5371e70651a53ed5ad000055"),
"course_id" : ObjectId("5371e2e051a53ed5ad000039"),
"course_member_ids" : [
ObjectId("5371e2a751a53ed5ad00002d"),
ObjectId("5371e2b251a53ed5ad000030"),
ObjectId("5371e2bb51a53ed5ad000033")
],
"created_at" : ISODate("2014-05-13T09:33:58.042Z"),
"current_user" : "51b473bf6986aee9c0000002",
"description" : "Schulung 1 / Elektro",
"fill_out" : ISODate("2014-04-30T22:00:00.000Z"),
"place" : "TEST",
"title" : "Schulung 1",
"updated_at" : ISODate("2014-05-13T09:33:58.811Z"),
"user_ids" : [
ObjectId("51b473bf6986aee9c0000002"),
ObjectId("521d7f606986ae4826000002"),
ObjectId("521d8b3f6986aed678000007")
]
}
Since course_member_ids is an array of course members you should test for equality. In shell syntax:
{$match:{"_id.course_member_ids":<valueYouWantToTest>}}
You don't need $in as this query is analogous to a find when you want to select documents that have a particular single value you are looking for.

Is it possible to query MongoDB, using ONLY Array([x][y[x][z]]) Approach? NOT knowing Elements' Content?

This is the first of 7 test/example documents, in collection "SoManySins."
{
"_id" : ObjectId("51671bb6a6a02d7812000018"),
"Treats" : "Sin1 = Gluttony",
"Sin1" : "Gluttony",
"Favourited" : "YES",
"RecentActivity" : "YES",
"GoAgain?" : "YeaSure."
}
I would like to be able to query to retrieve any info in any position,
just by referring to the position. The following document,
{
"_id" : ObjectId("51671bb6a6a02d7812000018"),
"Sin1" : "Gluttony",
"?????????" : "??????",
"RecentActivity" : "YES",
"GoAgain?" : "YeaSure."
}
One could retrieve whatever might be in the 3rd key~value
pair. Why should one have to know ahead of time what the
data is, in the key? If one has the same structure for the
collection, who needs to know? This way, you can get
double the efficiency? Like having a whole lot of mailboxes,
and your app's users supply the key and the value; your app
just queries the dbs' documents' arrays' positions.
Clara? finally? I hope?
The sample document you've provided is not saved as an array in BSON:
{
"_id" : ObjectId("51671bb6a6a02d7812000018"),
"Sin1" : "Gluttony",
"?????????" : "??????",
"RecentActivity" : "YES",
"GoAgain?" : "YeaSure."
}
Depending on the MongoDB driver you are using, the fields here are typically represented in your application code as an associative array or hash. These data structures are not order-preserving so you cannot assume that the 3rd field in a given document will correspond to the same field in another document (or even that the same field ordering will be consistent on multiple fetches). You need to reference the field by name.
If you instead use an array for your fields, you can refer by position or select a subset of the array using the $slice projection.
Example document with an array of fields:
{
"_id" : ObjectId("51671bb6a6a02d7812000018"),
"fields": [
{ "Sin1" : "Gluttony" },
{ "?????????" : "??????" },
{ "RecentActivity" : "YES" },
{ "GoAgain?" : "YeaSure." }
]
}
.. and query to find the second element of the fields array (a $slice with skip 1, limit 1):
db.SoManySins.find({}, { fields: { $slice: [1,1]} })
{
"_id" : ObjectId("51671bb6a6a02d7812000018"),
"fields" : [
{
"?????????" : "??????"
}
]
}
This is one way to Query and get back data when you may not
know what the data is, but you know the structure of the data:
examples in Mongo Shell, and in PHP
// the basics, setup:
$dbhost = 'localhost'; $dbname = 'test';
$m = new Mongo("mongodb://$dbhost");
$db = $m->$dbname;
$CursorFerWrites = $db->NEWthang;
// defining a set of data, creating a document with PHP:
$TheFieldGenerator = array( 'FieldxExp' => array(
array('Doc1 K1'=>'Val A1','Doc1 K2'=>'ValA2','Doc1 K3'=>'Val A3'),
array('Doc2 K1'=>'V1','Doc2 K2'=>'V2','Doc2 K3'=>'V3' ) ) ) ;
// then write it to MongoDB:
$CursorFerWrites->save($TheFieldGenerator);
NOTE : In the Shell : This produces the same Document:
> db.NEWthang.insert({"FieldxExp" : [
{"Doc1 K1":"Val A1","Doc1 K2":"Val A2","Doc1 K3":"Val A3"},
{"Doc2 K1":"V1", "Doc2 K2":"V2","Doc2 K3":"V3"}
]
})
#
Now, some mongodb Shell syntax:
> db.NEWthang.find().pretty()
{
"_id" : ObjectId("516c4053baa133464d36e836"),
"FieldxExp" : [
{
"Doc1 K1" : "Val A1",
"Doc1 K2" : "Val A2",
"Doc1 K3" : "Val A3"
},
{
"Doc2 K1" : "V1",
"Doc2 K2" : "V2",
"Doc2 K3" : "V3"
}
]
}
> db.NEWthang.find({}, { "FieldxExp" : { $slice: [1,1]} } ).pretty()
{
"_id" : ObjectId("516c4053baa133464d36e836"),
"FieldxExp" : [
{
"Doc2 K1" : "V1",
"Doc2 K2" : "V2",
"Doc2 K3" : "V3"
}
]
}
> db.NEWthang.find({}, { "FieldxExp" : { $slice: [0,1]} } ).pretty()
{
"_id" : ObjectId("516c4053baa133464d36e836"),
"FieldxExp" : [
{
"Doc1 K1" : "Val A1",
"Doc1 K2" : "Val A2",
"Doc1 K3" : "Val A3"
}
]
}
Finally, how about write the Query in some PHP ::
// these will be for building the MongoCursor:
$myEmptyArray = array();
$TheProjectionCriteria = array('FieldxExp'=> array('$slice' => array(1,1)));
// which gets set up here:
$CursorNEWthang1 = new MongoCollection($db, 'NEWthang');
// and now ready to make the Query/read:
$ReadomgomgPls=$CursorNEWthang1->find($myEmptyArray,$TheProjectionCriteria);
and the second document will be printed out:
foreach ($ReadomgomgPls as $somekey=>$AxMongoDBxDocFromCollection) {
var_dump($AxMongoDBxDocFromCollection);echo '<br />';
}
Hope this is helpful for a few folks.