У меня есть список списков, вот так:

li = [[('A', 'one'), ('A', 'two')], [('B', 'three'), ('B', 'four')]]

И мне нужно запросить базу данных mongo, чтобы получить все объекты, поле списка которых содержит хотя бы ОДИН элемент в каждом подсписке li. Пример: элементы, содержащие либо [('A', 'one') OR ('A', 'two')] И либо [('B', 'three') OR ('B', 'four')] ...

Я использую mongoengine, но это может измениться, если я смогу использовать что-то еще, чтобы сделать это. Итак, прямо сейчас я делаю много таких запросов, чтобы избежать дублирования записей:

final = set()
for sublist in li:
    query = Obj.objects(list_field__in=sublist)
    final &= set(query)

Проблема в том, что это очень медленно при работе с большими результатами запроса (я считаю, что создание набора занимает очень много времени). Есть ли способ ускорить это? В частности, есть ли способ избежать создания набора / списка из результатов запроса?

Очень хотелось бы иметь возможность как-то написать что-нибудь вроде этого:

query = Obj.objects(list_field__in=li[0] AND list_field__in=li[1] AND ...)

Изменить: ответ ниже не работает при дальнейшем тестировании, потому что mongoengine не позволяет Q(field=x) & Q(field=y)

Edit2: Вот эквивалентный запрос mongoDB, который я хочу сделать:

db.obj.find({ "$and": [
    {"list_field": {"$in":
        [["A", "one"], ["A", "two"]]
    }},
    {"list_field": {"$in":
        [["B", "three"], ["B", "four"]]
    }}
]})

Могу ли я сделать это в mongoengine? Это не позволит мне сделать запрос с Q(list_field__in=[('A', 'one'), ('A', 'two')]) | Q(list_field__in=[('B', 'three'), ('B', 'four')])

4
William 28 Янв 2013 в 18:40

1 ответ

Лучший ответ

Я думаю, вы можете попробовать это через класс Q :

  filter = reduce(Q.__and__, map(lambda x: Q(list_field__in=x), li))
  Obj.objects(filter)
5
sneawo 28 Янв 2013 в 19:19
Я считаю, что это именно то, что мне нужно! Мне тоже нравится использование reduce, но я помещу ваш более подробный ответ в этот комментарий на случай, если кто-то это предпочтет. filter = Q() for sublist in li: filter = filter & Q(list_field__in=sublist) Obj.objects(filter)
 – 
William
28 Янв 2013 в 19:31
На самом деле, когда я пытаюсь выполнить более сложный запрос, он не работает. Я получаю InvalidQueryError, потому что он не позволяет иметь Q(list_field__in=x) & Q(list_field__in=y), поскольку list_field одинаков в обоих Q.
 – 
William
29 Янв 2013 в 01:56
Не могли бы вы попробовать: filter = Q() for subli in li: subfilter = Q() for elem in subli: subfilter = subfilter | Q(list_field=elem) filter = filter & subfilter
 – 
sneawo
29 Янв 2013 в 13:45
Я уже пробовал именно это, но это тоже не позволяет.
 – 
William
29 Янв 2013 в 17:28