2

I'm trying to convert this query into an array, so i can use in PHP, but i'm stuck with the 'index' problem... As you can see, i need multiples '$or', because each '$or' validates a set of fields, and i can't join them all in the same '$or'.

Here is the query object:

{
'$and' : [
      { '$or' : [
          {'author' : { '$exists' : false } }
        , {'author' : { '$in' : [ 'john' , false ] } }
    ] }
    , {'$or' : [
          { '$and' : [ { 'type' : 'post' } , { 'user_id' : 123456 } ] }
        , { 'type' : 'comment' }
    ] }
    , { '$or' : [
          { 'tags.name' : { '$in' : [ 'tag1' , 'tag2' ] } }
        , { 'tags' : false }
        , { 'tags' : { '$exists' : false } }
    ] }
]
}

The first set of '$or' validates the 'author' field, so i'm searching any document with 'john' or false in the field, and i want the documents that doesn't have the 'author' field. The second set validates the 'type' field, where i need the documents that have 'comment' as value or 'post' AND the 'user_id' is 123456. The third set validates the 'tags' field, where i need some 'tags.name' inside an '$in' or 'tags' = false or 'tags' doesn't exists...

These 3 sets must be true, that's why they're all in the '$and' operator... I'm aware that '$and' works only in 2.0+, but i'm using 2.1 (aggregation frawework testing... it just ROCKS! XD)

I think that's it... if there's another way of writing the query i would reeeally like to see... thanks!

1
  • This query will always do a full collection scan because you're using {$exists:false}. This will be slow To rewrite the query to be more efficient, you'll need to change your schema. Commented Jul 27, 2012 at 17:05

1 Answer 1

5

Here is your query in PHP

$conn = new Mongo("localhost:$port");
$db = $conn->test;
$collection = $db->tb;

$or1 = 
    array( '$or' => array(
            array( 'author' => array( '$exists' => false ) ) ,
            array( 'author' => array( '$in' => array('john', false) ) ) 
          ));

$or2 = 
    array( '$or' => array(
        array( '$and' => 
                array( 
                    array( 'type' => 'post') ,
                    array( 'userid' => 123456 )
                    )
            ),
            array( 'type' => 'comment') 
        ));

$or3 = 
    array( '$or' => array(
            array( 'tags.name' => array( '$in' => array('tag1', 'tag2') ) ) ,
            array( 'tags' => false ), 
            array( 'tags' => array( '$exists' => false ) ) 
        ));

$query = array( '$and' => array( $or1, $or2, $or3 ) );


$cursor = $collection->find($query);
foreach( $cursor as $doc ) {
    // do something
}
Sign up to request clarification or add additional context in comments.

2 Comments

That reeeealy makes sense!! Thanks!!
This was exactly what I was looking for. I was trying to create it all in one array and it was getting ugly. Thanks so much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.