Nodejs + mongodb: how to request $ ref fields?

I use MongoDB using the nodejs REST service, which provides my data stored internally. I have a question on how to poll my data that use $ ref.

Here is an example of an object that contains a link to another object (part) in the anther collection:

{ "_id" : ObjectId("5962c7b53b6a02100a000085"), "Title" : "test", "detail" : { "$ref" : "ObjDetail", "$id" : ObjectId("5270c7b11f6a02100a000001") }, "foo" : bar } 

Actually, using Node.js and the mongodb module, I do the following:

 db.collection("Obj").findOne({"_id" : new ObjectID("5962c7b53b6a02100a000085"}, function(err, item) { db.collection(item.$ref).findOne({"_id" : item.$id}, function(err,subItem){ ... }); }); 

In fact, I make 2 requests and get 2 objects. This is a kind of "lazy load" (not really, but almost)

My question is simple: is it possible to get the entire graph of an object in one query?

thanks

+8
javascript mongodb dbref
source share
5 answers

Vladimir’s answer is still not valid, since the db.dereference method has been removed from the MongoDB Nodejs API:

https://www.mongodb.com/blog/post/introducing-nodejs-mongodb-20-driver

The db instance object has been simplified. We have removed the following methods:

db.dereference because db links are out of date on the server

+1
source share

No, you can’t.

To enable DBRefs, your application must fulfill additional queries to return the reference documents. Many drivers have helper methods that automatically generate a query for DBRef. Drivers do not automatically allow DBRefs to documents.

From MongoDB docs http://docs.mongodb.org/manual/reference/database-references/ .

+4
source share

Is it possible to get the parent object with it $ ref using a single MongoDB query?

No, It is Immpossible. Mongo has no internal link support, so it's up to your application to populate them (see Brett's answer ).

But is it possible to get the parent object with all its ref with a single node.js command?

Yes it is possible. You can do this with Mongoose . It has built-in population support. You need to slightly modify your data model to make it work, but that is pretty much what you are looking for. Of course, for this, Mongoose will make the same two MongoDB queries as you.

+4
source share

No, very few drivers for MongoDb include special support for DBRef . There are two reasons:

  • MongoDb does not have special commands to make the search for referenced documents possible. Thus, drivers that add support artificially populate the resulting objects.
  • The larger the bare metal API, the less it makes sense. Actually, like. MongoDb collections have no schema, if the NodeJs driver returned the primary document with all the links implemented, if the code then saved the document without breaking the links, this will lead to an embedded document. Of course it will be a mess.

If the field values ​​change, I would not worry about the DBRef type and instead just save the ObjectId directly. As you can see, DBRef really does not offer any advantages, except that each link requires a lot of duplicated disk space, since a richer object must be stored along with its type information. In any case, you should consider the potentially unnecessary overhead of storing a string containing collection reference documents.

Many developers and MongoDb, Inc. added an object document display layer on top of existing base drivers. One of the popular options for MongoDb and Nodejs is Mongoose. Since the MongoDb server does not have a real understanding of the referenced documents, the responsibility for the links is transferred to the client. Since most often a particular collection from this document is sequentially referenced, Mongoose allows you to define a link as a schema. Mongoose is not without a pattern.

If you agree that using and using a schema is useful, then Mongoose is definitely worth a look. He can effectively receive a package of related documents (from one collection) from a set of documents. It always uses its own driver, but it usually works extremely efficiently and takes some of the complexity out of more complex application architectures.

I would strongly suggest you take a look at the populate method ( here ) to see what it is capable of doing.

 Demo /* Demo would be a Mongoose Model that you've defined */ .findById(theObjectId) .populate('detail') .exec(function (err, doc) { if (err) return handleError(err); // do something with the single doc that was returned }) 

If instead of findById , which always returns a single document, find was used, when populate property of all returned documents details will be filled automatically. It is also smart that he will request the same reference documents several times.

If you are not using Mongoose, I would advise you to think about caching in order to avoid possible use of client-side links and use the $in query operator to batch load as much as possible.

+1
source share

I get the desired result in the following example:

 collection.find({}, function (err, cursor) { cursor.toArray(function (err, docs) { var count = docs.length - 1; for (i in docs) { (function (docs, i) { db.dereference(docs[i].ref, function(err, doc) { docs[i].ref = doc; if (i == count) { (function (docs) { console.log(docs); })(docs); } }); })(docs, i) } }); }); 

Not sure if this solution is the best, but this is the simplest solution I have found.

+1
source share

All Articles