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)