Pass DBRef in mongo query while fetching a document using java

SET picture SET · Oct 11, 2013 · Viewed 7.8k times · Source
 db.collectionB.findOne()
 {
    "_id" : NumberLong(24),
    "class" : "Top",
    "type" : DBRef("collectionA", NumberLong(47))
 }
db.collectionA.findOne()
{
   "_id" : NumberLong(47),
   "name" : "John",
   "position" : 2 
}

QUERY to be formed : db.collectionB.find({type: DBRef("collectionA", NumberLong(47))});

There are a number of documents in collection A & collectionB. I want to search the documents where "type" in collectionB is referring to document where "_id" is NumberLong(47) in collectionA.

BasicDBObject query =   new BasicDBObject("name","John");
DBObject db_object = findOne("collectionA",query);
DBRef myDbRef = new DBRef(db,"collectionB",db_object); 
DBObject doc = myDbRef.fetch(); 
System.out.println(doc);

It gives the output null. Why?

Answer

Philipp picture Philipp · Oct 11, 2013

The 3-argument constructor of DBRef takes the following arguments:

  • Database
  • Namespace
  • ID

Your second argument isn't a namespace, it is just the collection. It should be a string "yourDatabaseName.collectionB".

Your third argument isn't just an ID, it's a complete object. That way the DBRef points to a document where the value of the field _id is a complete copy of the document you pass. Such a document doesn't exist, so fetching the DBRef returns null.

To create a valid DBRef you only pass the value of _id to the constructor of DBRef.

But when I understood your requirement "I want to search the documents where "type" in collectionB is referring to document where "_id" is NumberLong(47) in collectionA." correctly, you don't even have to query collectionA. DBRef's are just transparent sub-objects with this structure: { "$ref" : <value>, "$id" : <value>, "$db" : <value> }. So you should be able to find the desired documents with:

db.collectionB.find("type.$id": 47);

This assumes that all the dbref's under type reference the same collection and database. When that's not the case, you need to include these in your query to avoid results referencing another collection:

db.collectionB.find("type.$id": 47, "type.$ref": "collectionA", "type.$db": <database name>);