Question

I am trying to make a search on several field where some of them can be left blank. Given the following Json document in MongoDB (only three fields here, but N fields in reality, with N > 10) :

{
    'first_name' : 'value_X',
    'last_name' : 'value_Y',
    'mail_adress' : 'value_Z'

}

Then let's suppose a form where the user can enter the value of the first name, last name, mail address and phone number. If all the field are filled the query in MongoDB looks like :

db.collection.find( {
                        'first_name' : 'value_A',
                        'last_name' : 'value_B',
                        'mail_adress' : 'value_C'

                    }
                )

The problem I have is that I might have some fields left blank by the user : It means that my query can also become :

db.collection.find({ 'first_name' : 'value_A' })

or

db.collection.find( {'last_name' : 'value_B'})  

or

db.collection.find( {'mail_adress' : 'value_C'})

or

db.collection.find( {'first_name' : 'value_A','last_name' : 'value_B'})

or

db.collection.find( {'first_name' : 'value_A','last_name' : 'value_C'})

or

db.collection.find( {'last_name' : 'value_B','mail_adress' : 'value_C'})

I would like to know if I need to write a query for each particular instance ? I also thought to generate query dynamically depending on the field entered by a user, it would be easy as query are Json doucment.

I am also wondering if MongoDB could ignore field if they are null (but I don't want to lose performance in my query)

Anyone can help me ? Thanks

EDIT on 20140404 at 6PM : part of answer

Here is the Python code with Aditya suggestion. I also added the python code about generating the query in front end as svjn suggested:

'''
Created on 4 Apr 2014

@author: scoulombel
'''

import pymongo
from pymongo import MongoClient
import random
import string



# fill the database
def fillCollection(collection):
    doc =   {
      'first_name' : 'value_X',
      'last_name' : 'value_Y',
      'mail_adress' : 'value_Z'

    }

    docID = collection.insert(doc)

    for _ in range(0,10):
        doc = {
           'first_name' : ''.join(random.choice(string.ascii_uppercase) for _ in range(4)) + ''.join(random.choice(string.digits) for _ in range(4)),
           'last_name' : ''.join(random.choice(string.ascii_uppercase) for _ in range(4)) + ''.join(random.choice(string.digits) for _ in range(4)),
           'mail_adress' : ''.join(random.choice(string.ascii_uppercase) for _ in range(4)) + ''.join(random.choice(string.digits) for _ in range(4))

        }
        docID = collection.insert(doc)

# read data in a cursor
def readCursor(cursor):
    object_list = []
    count = 0   
    for doc in cursor :
        del doc["_id"]
        count += 1
        doc['resOrder'] =  count
        object_list.append(doc)

    print object_list

if __name__ == '__main__':  
    #client = MongoClient()
    client = MongoClient('ip', 'port')
    db = client.test_OR_AND_DB      
    collection = db.collection

    fillCollection(collection)

    # SEARCH VALUE which can be null or not    
    value_A = 'value_X'
    value_B = 'null' #'value_Y'
    value_C = 'null' #'value_Z'

    # APPROACH 1 : ADITYA answer for search
    cursor1 = db.collection.find(
                                {
                         '$or' : [
                                    { '$and' : [ {'first_name' : { '$ne': 'null' }}, {'first_name' : value_A } ]},
                                    { '$and' : [ {'last_name' :  { '$ne': 'null' }}, {'last_name'  : value_B  } ]}, 
                                    { '$and' : [ {'mail_adress' :{ '$ne' :'null' }}, {'mail_adress':value_C } ]}
                               ]
                        }
                        )

    readCursor(cursor1)

    # APPROACH 2 ; create a JSON representing the query dynamically
    path_value_dict = {'first_name':value_A, 'last_name':value_B, 'mail_address':value_C} # if embedded it would be for instance name.first_name 
    query= {}
    for key in path_value_dict.keys():
        if path_value_dict[key] != 'null':
            query[key] = path_value_dict[key]


    print query
    cursor2 = db.collection.find({'first_name': 'value_X', 'mail_adress': 'value_Z'})
    readCursor(cursor2) 
Was it helpful?

Solution

Use Mongodb $or operator for your query.

The $or operator performs a logical OR operation on an array of two or more <expressions> and selects the documents that satisfy at least one of the <expressions>.

Use :

db.collection.find({
     $or : [{ $and : [ {'first_name' : { $ne:null }, {'first_name' :'value_A' }]},
            { $and : [ {'last_name' :  { $ne:null }, {'last_name'  :'value_B' }]}, 
            { $and : [ {'mail_addres' :{ $ne:null }, {'mail_addres':'value_C'}]}
           ]}
    );
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top