2015-06-30 3 views
4

Я пытаюсь запросить коллекцию базы данных, которая содержит документы процессов для тех документов, которые имеют определенные поля. Для простоты представьте следующую общую схему документа:Проверить наличие нескольких полей в документе MongoDB

{ 
    "timestamp": ISODate("..."), 
    "result1": "pass", 
    "result2": "fail" 
} 

Теперь, когда процесс запущен новый документ вставляется только с отметкой времени. Когда этот процесс достигает определенных этапов, поля result1 и result2 добавляются с течением времени. Однако некоторые процессы не доходят до этапов 1 или 2 и поэтому не имеют полей результатов.

Я хотел бы запросить базу данных, чтобы получить только те документы, которые имеют ОБА result1 и result2.

Я знаю об операторе $exists, но насколько я могу сказать, это работает только для одного поля за раз, то есть db.coll.find({"result1": {$exists: true}}). Оператор $exists не может использоваться как оператор верхнего уровня. Например. это делает не работы:

db.coll.find({"$exists": {"result1": true, "result2": true}})

Для проверки обоих результатов я должен был бы:

db.coll.find({"result1": {"$exists": true}, "result2": {"$exists": true}})

Теперь, когда уже становится утомительным для более одна переменная.

Есть ли лучший способ сделать это? (Кроме того, я делаю это в Python, так что если есть решение для всего водителя PyMongo, что сделало бы меня счастливым уже.)

+0

См http://stackoverflow.com/questions/43898220/pymongo-aggregate-filter-by-count-of-fields-number-dynamic для агрегации (стороне сервера) решение. –

ответ

2

Я не знаю, о лучше, но вы всегда можете обрабатывать с JavaScript с помощью :

jsStr = """var doc = this; 
      return ['result1','result2','result3'] 
      .every(function(key) { 
       return doc.hasOwnProperty(key) 
      });""" 

coll.find({ "$where": jsStr }) 

Но вы будете иметь, чтобы указать массив «ключей», чтобы проверить где-нибудь.

Если вы думаете, у вас есть много ключей, чтобы впечатать, то почему бы не просто «строить» ваше выражение запроса:

whitelist = [ "result1", "result2", "result3" ] 
query = {} 

for key in whitelist: 
    query[key] = { "$exists": True } 

coll.find(query) 

Это экономит немного типизации и так как все запросы MongoDB являются только структуры данных в любом случае, использование базовых манипуляций с данными для создания запросов имеет смысл.

+0

Спасибо. Это работает хорошо, и именно это я и делал тем временем. В вашем цикле for я думаю, что вы хотите иметь: query [key] = ... – pnd

1

Как об использовании $and:

db.coll.find({"$and": [                  
      { "fld1": { "$exists": true }}            
      , { "fld2": { "$exists": true }}            
      , { "fld3": { "$exists": true }}            
]}) 
+0

Этот тип повторяющегося списка 'fields +" существует ": true' - это то, чего я хочу избежать, и добавление $ и запроса не делайте это лучше, просто более запутанным. См. Ответ Blakes Seven о том, как автоматизировать построение запроса с помощью простого цикла. – pnd

+0

Совершенно верно!Просто оставался в стиле с вашим оригинальным сообщением, которое использовало примеры CLI. Путь к программированию - построение запросов MongoDB. Хорошо использовать $ и оператор как часть этой логики кода, чтобы в целом обрабатывать все виды выражений запросов. –

Смежные вопросы