Mongodb : find documents including references to sub-documents [node-mongodb-native] - mongodb

I have the following Mongodb Documents :
Users : {'_id' : '12345', 'fullname' : 'ABC'}
and
Files :
{'_id' : 'File001', 'path' : 'pathA', 'Users_id' : '12345'}
{'_id' : 'File002', 'path' : 'pathB', 'Users_id' : '12345'}
How do i query or find all 'Files' documents in a way that the 'Users_id' which is referencing to the 'Users' document has the full 'Users' Document?
Expected Output :
{'_id' : 'File001', 'path' : 'pathA', 'Users_id' : '12345', 'user' : {'_id' : '12345', 'fullname' : 'ABC'}}
{'_id' : 'File002', 'path' : 'pathB', 'Users_id' : '12345', 'user' : {'_id' : '12345', 'fullname' : 'ABC'}}
In this way, i could access the file owner's fullname as such : file.user.fullname
I Appreciate any help from you guys. Thank you.
--- EDIT
I am using node-mongodb-native to access the db.
Below is my code to retrieve it:
var files = db.collection ('Files');
files.find ({}, {}).toArray (function ( err, filesDoc){
for ( var index in filesDoc) {
var fileDoc = filesDoc [ index ];
var users = db.collection ('Users');
users.findOne ({'_id' : fileDoc.Users_id}, {}, function (errUser, userDoc){
if ( ! errUser ) {
fileDoc.user = userDoc;
}
});
}
});
but this code is not assigning the user to all files doc and only assigns to the last element of the filesDoc array. Any suggestions?

MongoDB doesn't support joins so you have to query for the User details separately. If you're using node.js, Mongoose provides a populate feature to help simplify this so you can do something like the following to pull in the user details:
Files.find().populate('Users_id')

I managed to find the cause of the issue. The reason why my code returns a null user is because I saved File.Users_id as String and I am retrieving it using ObjectId.
I fixed my codes by converting Users_id String to ObjectId before saving the File.

Related

How to find a document by looking for a match in an embedded document array?

This seems so simple but apparently I'm missing something. I've got a WebSite model:
class WebSite
include Mongoid::Document
has_many :domains, inverse_of: :web_site
field :name, type: String
end
The WebSite model has an embedded array of Domains:
class Domain
include Mongoid::Document
belongs_to :web_site, inverse_of: :domains
field :name, type: String
end
All I'm trying to do is find a WebSite with a domain of "test.com". Nothing I've tried seems to work, either with Mongoid or with the MongoDB console. For example, if I have one WebSite, with one Domain, with the name "test.com":
2.0.0p0 :001 > WebSite.count
=> 1
2.0.0p0 :002 > WebSite.first.domains
=> [#<Domain _id: 5148d9b76a3b8b1fe6000003, web_site_id: "5148d9a96a3b8b1fe6000002", name: "test.com">]
...then shouldn't this work?
2.0.0p0 :003 > WebSite.elem_match(domains: { name: "test.com" }).count
=> 0
2.0.0p0 :004 > WebSite.elem_match('domains' => { 'name' => "test.com" }).count
=> 0
I get zero. I should get one.
I also got the impression from the O'Reilly book that this should work:
2.0.0p0 :005 > WebSite.where('domains.name' => "test.com").count
=> 0
...same with any_in:
.0.0p0 :006 > WebSite.any_in('domains' => { 'name' => "test.com" }).count
=> 0
I've also tried those same queries from the MongoDB console with the same results:
> db.web_sites.find({"domains" : {"$elemMatch" : {"name" : "test.com"}}}).size();
0
> db.web_sites.find({"domains.name" : "test.com"}).size();
0
> db.web_sites.find({"domains" : {$in : {"name" : "test.com"}}}).size();
0
I must be missing something?
Update:
Here is some more information about the schema, from the MongoDB console:
> db.web_sites.find().pretty()
{ "_id" : ObjectId("5148d9a96a3b8b1fe6000002"), "name" : "test" }
Thanks to uldall's help with debugging (that awesome pretty() technique) I realized that my problem was that I had two separate collections side by side, instead of a Domain collection embedded in my WebSite collection. This is how my models should have been set up, with "embedded_in" and "embeds_many":
class WebSite
include Mongoid::Document
embeds_many :domains, inverse_of: :web_site
field :name, type: String
end
class Domain
include Mongoid::Document
embedded_in :web_site, inverse_of: :domains
field :name, type: String
end
Now the document looks like this from the MongoDB console:
> db.web_sites.find().pretty()
{
"_id" : ObjectId("5148e63f6a3b8b8ffa000001"),
"domains" : [
{
"_id" : ObjectId("5148e6706a3b8b8ffa000002"),
"name" : "test.com"
}
],
"name" : "test"
}
With that schema, this works:
2.0.0p0 :008 > WebSite.where('domains.name' => 'test.com').count
=> 1
[CHEER]

About upsert in pymongo

Each record in the collection has two key "ip" and "timestamp"
db.posts.update({'ip' : '127.0.0.1', 'timestamp' : {'$gt' : sometimestamp}}, {'$set' : {'timestamp' : time.time()}, True)
The command above will insert a new record, if field "ip" with "127.0.0.1" not in the collection or "timestamp" is less than sometimestamp
Now, if I want to insert a new record only "ip" with "127.0.0.1" not in collection, in other word, keep value of "ip" unique.
How to do ?
What you are probably trying to do is this:
if( ip=127)
if( ts > myts)
update;
else
DO NOTHING;
else
insert;
So essentially, you are having two different types of updates..One is going to acutally make a change in timestamp and other tells mongo to do nothing, i.e., not even make an insert.
I am guessing this is not possible with an upsert. So better use simple updates as follows:
db.posts.update ( { 'ip' : '127.0.0.1', 'timestamp' : { '$gt' : sometimestamp } } , { '$set' : { 'timestamp' : time.time() } , False)
And I don't know how you'd write it in Pymongo, but logically speaking, you do this:
if (db.posts.find_one( { 'ip':'127.0.0.1'} ) != null):
db.posts.update ( {'ip' : '127.0.0.1'}, { '$set' : {'timestamp' : time.time() } } )
Unfortunately, I can't comment on the performance..

PHP MongoDB insertion issue

having this weird issue while inserting to MongoDB using PHP. My insertion code is as follows :
$tyre = array("m" => '5', "i" => 'test.png');
$tyreCollection->insert(array($tyre),array('safe'=>true));
After insertion, I see the following in my DB :
{'_id' : ObjectId("856876876786867"),"0":{"m":'5','i':'test.png'}}
Why does my new array have a key of 0 ? I am expecting :
{'_id' : ObjectId("856876876786867"),"m":'5','i':'test.png'}
What am I doing wrong ?
Insert only $tyre instead of array($tyre)
$tyreCollection->insert($tyre,array('safe'=>true));
Also always remember to dump variables with var_dump or print_r

Perl and MongoDB update issue

i tried to use https://metacpan.org/release/MongoDB module over perl and found a small bug or i haven't enough material on doc
this is where i got error
{ "_id" : ObjectId("4f625c0fcd4481bc13000000"), "mode" : "running", "res" : "running", "custid":NumberLong(155655062)}
db.movie.update({custid:NumberLong(155655062)},{'$set':{mode:"testing"}});
I am able to update the thing here but not able to update from perl code.
my $res = $db->movie->update({'custid'=>'NumberLong(155655062)'},{'$set' => { 'mode' => 'testing' }});
did i miss any code in the above example
my $cust_id = 155655062; OR my $cust_id = int($record->{custid});
my $res = $db->movie->update({'custid'=>$cust_id},{'$set' => { 'mode' => 'testing' }});
Try this, it should work.

Why $pull operator doesn't work on MongoDB when using empty criteria?

I have nodes like this:
[_id] => MongoId Object (
[$id] => 4e90cb3cd68417740c000017
)
[label] => mystery
[owner] => me
[parents] => Array (
[0] => Array (
[id] => MongoId Object (
[$id] => 4e8c6bb6d68417340e0004ca
)
[owner] => userid
[timestamp] => 1318112522
)
)
[timestamp] => 1318112060
[translabel] => mystery
[type] => 0
What I am trying to do is to remove parents with id : 4e8c6bb6d68417340e0004ca , wherever they are.
For example this should have been working (latest Mongo):
db.nodes.update({},{$pull : {"parents": { "id" : ObjectId("4e8c6bb6d68417340e0004ca") }}});
or equaly in PHP (latest driver etc):
$mongodb->nodes->update(array(),array('$pull'=> array('parents'=>array('id'=> new MongoId("4e8c6bb6d68417340e0004ca")))));
both don't do anything!
on the other hand:
db.nodes.update({"_id": ObjectId("4e90cb3cd68417740c000017")},{$pull : {"parents": { "id" : ObjectId("4e8c6bb6d68417340e0004ca") }}});
or equaly in PHP:
$mongodb->nodes->update(array('_id' => new MongoId("4e90cb3cd68417740c000017"),array('$pull'=> array('parents'=>array('id'=> new MongoId("4e8c6bb6d68417340e0004ca")))));
work perfectly well! Is this a bug? Is it a problem that I use "id" instead of "_id" with MongoID objects in my subdocuments? Thanks in advance for any help!
Have you tried enable multi flag on update command
db.collection.update( criteria, objNew, upsert, multi )
multi - indicates if all documents matching criteria should be updated rather than just one. Can be useful with the $ operators below.
and change your query to
db.nodes.update({},{$pull : {"parents": { "id" : ObjectId("4e8c6bb6d68417340e0004ca") }}},false,true);
or
db.nodes.update({ "_id" : { $exists : true } },{$pull : {"parents": { "id" : ObjectId("4e8c6bb6d68417340e0004ca") }}},false,true);
i haven't tested the code myself, but am sure that any one of the above will work..