Невозможно сделать это в одном запросе. Вы должны искать документ в первом запросе:
Если существует документ:
db.bar.update( {user_id : 123456 , "items.item_name" : "my_item_two" } ,
{$inc : {"items.$.price" : 1} } ,
false ,
true);
Else
db.bar.update( {user_id : 123456 } ,
{$addToSet : {"items" : {'item_name' : "my_item_two" , 'price' : 1 }} } ,
false ,
true);
Не нужно добавлять условие {$ne : "my_item_two" }
.
Также в многопоточной среде вы должны быть осторожны, чтобы только один поток мог выполнить второй (вставить регистр, если документ не был найден) за раз, в противном случае будут вставлены дублирующие вложенные документы.
sum(x.b == 1 for x in L)
Логическое (как результат сравнений, таких как x.b == 1
) также является int
, со значением 0
для False
, 1
для True
, поэтому арифметика, такая как суммирование работает просто отлично.
Это самый простой код, но, возможно, не самый быстрый (наверняка вам скажет только timeit
;-). Рассмотрим (упрощенный случай, чтобы хорошо вписаться в командные строки, но эквивалентно):
$ py26 -mtimeit -s'L=[1,2,1,3,1]*100' 'len([x for x in L if x==1])'
10000 loops, best of 3: 56.6 usec per loop
$ py26 -mtimeit -s'L=[1,2,1,3,1]*100' 'sum(x==1 for x in L)'
10000 loops, best of 3: 87.7 usec per loop
Таким образом, для этого случая «расточительный в памяти» подход генерации дополнительного временного списка и проверки его длины на самом деле значительно быстрее чем более простой, короткий, бережливый к памяти, который я предпочитаю. Разумеется, другие комбинации значений списка, реализации Python, доступность памяти для «ускорения» этого ускорения и т. Д. Могут, конечно, повлиять на точную производительность.
Я бы предпочел второй, так как он перебирает список только один раз.
Если вы используете count()
, вы перебираете список один раз, чтобы получить значения b
, а затем снова зацикливаете его, чтобы увидеть, сколько из них равно 1.
Аккуратный способ может использовать reduce()
:
reduce(lambda x,y: x + (1 if y.b == 1 else 0),list,0)
Документация говорит нам, что reduce()
будет:
Применить функцию два аргумента в совокупности с элементами итерируемого слева направо, чтобы свести итерируемое к одному значению.
Таким образом, мы определяем lambda
, который добавляет одно накопленное значение, только если атрибут элемента списка b
равен 1.