简体   繁体   中英

MongoDB: Querying multiple collections with two queries?

I've two collections posts and authors . A post document contains, beside the post data, a DBref link ID to an author _id . My collection looks like this:

posts

  "_id" : ObjectId("4fa12443d3269e98070013b4"),
  "author" : {
    "$ref" : "authors",
    "$id" : ObjectId("4fa1242bd3269e9807000023")
  },
  "post" : " mi eleifend egestas. Sed pharetra, felis eget varius ultrices, mauris ipsum porta elit, a feugiat tellus lorem eu metus. In lorem.",
  "post_title" : "Volutpat. Nulla facilisis. Suspendisse commodo tincidunt nibh. Phasellus nulla. Integer",
  "date" : 1293803276,
  "rating" : 8,
  "comments" : [{
      "name" : "Doris Turner",
      "email" : "Hedda_Herman@.com",
      "upVotes" : 81,
      "downVotes" : 93,
      "comment_date" : 1111395830,
      "comment" : "consectetuer ipsum nunc id enim. Curabitur massa. Vestibulum accumsan neque et nunc. Quisque ornare tortor at"
    }, {
      "name" : "Brenda Tyler",
      "upVotes" : 1,
      "downVotes" : 73,
      "comment_date" : 940325674,
      "comment" : "cursus purus. Nullam scelerisque neque sed sem egestas blandit. Nam Nulla aliquet. Proin velit. Sed malesuada augue ut lacus. Nulla tincidunt, neque vitae semper egestas, urna justo faucibus lectus, a sollicitudin orci sem eget massa."}],
  "tags" : ["tag1", "tag3"]
}  

And my authors collection looks like this:

authors

{
  "_id" : ObjectId("4fa1242bd3269e9807000016"),
  "name" : "Kristina Chung ",
  "email" : "curran_ramos@google.co.id\r\n.dk",
  "age" : 60,
  "city" : "Copenhagen"
}

I'm trying to create a “relational” query to find: Posts with rating greater than 6 and less than 9 and where the post author age is greater than 19 and less than 25.

I'm trying to aggregate this but can't seem to get the right data.

The first query is in my posts collection and looks like this:

$query = array('rating' => array('$gte' => 6, '$lt' => 9), 'comments.upVotes' => array('$gt' => 2, '$lt' => 20));

I selects the author.$id field which is the reference to the authors collection.

I then put all the $id's in a array as such:

while ($cursor->hasNext()): $document = $cursor->getNext();
    $authorID[] = $document['_id'];
endwhile;

and then I try to find the correct number with this query in the authors collection

$query2 = array('age' => array('$gte' => 19, '$lt' =>100), '_id' => array('$in' => $authorID));
$cursor = q('author')->find($query2);

I try to get the total number with this code: $count = $cursor->count(); but no matter what query I try to run I always get the result 0 .

What am I doing wrong and can is it possible at all to create this kind of query or do I have to make it on application level instead of database level?

And I'm well aware of embedded documents, but I want to have these two collections separated and not embed it.

Hope anyone can help me with this.

Sincere
- Mestika

Trying to 'create a “relational” query' in MongoDB is going to be an exercise in frustration. Your schema stores some information (the post's rating) in one collection and other information (the author's age) in a different collection, but all MongoDB queries operate on single collections. Unless you denormalize your data (which you said you did not want to do), you will need a two-pass method to make this work.

An approach that should work would be to build an array of author IDs and use it in a query of the posts collection using '$in'. Here's what it might look like in JavaScript using the mongo shell:

> var authorList = [];
> var authorCursor = db.authors.find({age:{$gt:19,$lt:25}},{"_id":1});
> while(authorCursor.hasNext()){authorList.push(authorCursor.next()["_id"])};
> db.posts.find({"author.$id":{$in:authorList},rating:{$gt:6,$lt:9}});

The first line creates an empty array. The second line creates a cursor that will select the _id fields of all authors in your target age range. The third line uses the cursor to populate an array of author _id s. The fourth line displays all posts that match your target criteria: author _id in the list we just build and rating in the range you specified.

I don't know but sometimes, the cursor method, seems lose some elements so I prefer use toArray():

u = db.authors.find({"isActive":false}).toArray()
idlist = []
u.forEach(function(myDoc) { idlist.push(myDoc.ID ); } )
db.posts.find({"AuthorID": {$in : idlist} } )


u = db.authors.find({"isActive":false})
idlist2 = []
while (u.hasNext()) {idlist2.push(u.next()["ID"])};
idlist.forEach(function(myDoc) { 
   if ( idlist2.indexOf(myDoc) == -1 ) 
       {print (myDoc)} 
})

print 20 elements of !

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM