title: Speed up Pymongo query
body: <p>I'm using Python 3, Pymongo with mongodb 4.0 and <a href="https://github.com/OpenInformix/IfxPy" rel="nofollow noreferrer">Ifxpy</a> to query Informix database. I have 4 Collections in my MongoDB database :</p>
  
  <ul>
  <li>User</li>
  <li>Office</li>
  <li>Pet</li>
  <li>Car</li>
  </ul>
  
  <p>One User has one Office, one Pet and one Car. So I have 3 references on each field in the User collections.</p>
  
  <p>I need something like this : </p>
  
  <ul>
  <li>I want to find if there is a User with the name <code>John</code> and a Pet with the name <code>Mickey</code> and a Car with the model <code>Tesla</code> and with the status <code>inactive</code>. After that I'll just update the User status to <code>active</code>. I have to query the Office but I don't use it in this example.</li>
  </ul>
  
  <p>I created indexes for each fields :</p>
  
  <pre><code>office.create_index([("code", pymongo.DESCENDING)], unique=True)
  pet.create_index([("name", pymongo.DESCENDING)], unique=True)
  car.create_index([("model", pymongo.DESCENDING)], unique=True)
  user.create_index([("username", pymongo.DESCENDING)], unique=True)
  user.create_index([("pet", pymongo.DESCENDING)])
  user.create_index([("car", pymongo.DESCENDING)])
  user.create_index([("status", pymongo.DESCENDING)])
  </code></pre>
  
  <p>Here is my code :</p>
  
  <pre><code>office_id = None
  car_id = None
  pet_id = None
  ifx_connection = IfxPy.connect(ifx_param, "", "")
  stmt = IfxPy.exec_immediate(ifx_connection, sql)
  dictionary = IfxPy.fetch_assoc(stmt) # Get data key / value
  start = time.time()
  
  # Loop on informix data (20 000 items)
  while dictionary != False:
      # Trim all string in dict
      dictionary = {k: v.strip() if isinstance(v, str) else v for k,v in dictionary.items()}
  
      # Get office
      office_code = dictionary['office_code']
      existing_office = office.find_one({"code": office_code})
  
      if bool(existing_office):
          office_id = existing_office['_id']
  
      # Get pet
      existing_pet = pet.find_one({"name": dictionary['pet_name']})
      if bool(existing_pet):
          pet_id = existing_pet['_id']
  
      # Get car
      existing_car = car.find_one({"model": dictionary['car_model']})
  
      if bool(existing_car):
          car_id = existing_car['_id']
  
      # Get user
      existing_user = user.find_one({
          "username": dictionary['username'],
          "car": car_id,
          "pet": pet_id,
          "status" : "inactive"
      })
  
      if bool(existing_user):
          # Change user status
          user.update_one({'_id': existing_user['_id']}, {"$set": {"status" : "active"}}, upsert=False)
  
      # Next row
      dictionary = IfxPy.fetch_assoc(stmt)
  </code></pre>
  
  <p>If I remove the MongoDB code from the loop, it takes 1,33 seconds. And If I query MongoDB it takes 47 seconds. I have 20 000 items. I think it's really slow.</p>
  
  <p>I tried to see the time for each find_one with <code>start = time.time()
  </code> by removing all find_one and let just one. And if I let just Office find_one it takes ~12 seconds and same for the other. If I let just customer find_one it takes ~12 seconds too. So ~12 * 4 this is why it takes ~47 seconds for all find_one.</p>
  
  <p>Can you tell me what I'm doing wrong ?</p>