Pymongo или Mongodb обрабатывает два равных словаря python как разные объекты. Могу ли я заставить их лечиться одинаково?
Пожалуйста, просмотрите следующие строки кода и результаты:
import pymongo
d1 = {'p': 0.5, 'theta': 100, 'sigma': 20}
d2 = {'theta': 100, 'sigma': 20, 'p': 0.5}
I get the following results:
d1 == d2 // Returns True
collectn.find({'goods.H': d1}).count() // Returns 33
collectn.find({'goods.H': d2}).count() // Returns 2
где collectn
- объект коллекций Mongodb.
Есть ли способ или способ запроса, чтобы получить те же результаты
для вышеупомянутых двух запросов?
Они по существу используют один и тот же словарь (в
смысл d1 == d2
составляет True
). Я пытаюсь сделать следующее:
перед тем, как вставить запись в базу данных, я проверяю, есть ли
уже существует запись с добавленной точной комбинацией значений.
Если да, то я не хочу делать новую запись. Но из-за вышеизложенного
показанного поведения становится возможным получить, что запись не существует даже
когда это происходит, и дублирующая запись добавляется в базу данных (конечно, с разными _id
но все остальные значения одинаковы, и я бы предпочел не иметь этого).
Заранее благодарим вас за помощь.
Ответы
Ответ 1
Проблема, с которой вы столкнулись, объясняется в документации mongodb здесь. Это также связано с тем, что словари Python неупорядочены, а объекты MongoDB упорядочены объектами BSON.
Соответствующая цитата:
Соотношения равенства в поддокументах выбирают документы, если поддокумент соответствует точно указанному вложенному документу, включая порядок полей.
Я думаю, вам может быть лучше, если вы обрабатываете все три свойства как подпрограммы основного объекта, а не один набор свойств, который является подобъектом. Таким образом, упорядочение подобъекта не принудительно вводится в запрос интерпретатором python.
Например...
d1 = {'goods.H.p': 0.5, 'goods.H.theta': 100, 'goods.H.sigma': 20}
d2 = {'goods.H.theta': 100, 'goods.H.sigma': 20, 'goods.H.p': 0.5}
collectn.find(d1).count()
collectn.find(d2).count()
... может давать более согласованные результаты.
Наконец, способ сделать это меняет меньше кода:
collectn.find({'goods.H.' + k:v for k,v in d1.items()})
collectn.find({'goods.H.' + k:v for k,v in d2.items()})
Ответ 2
Я могу только подумать о двух вещах:
-
Создайте свой запрос следующим образом: collectn.find({'goods.H.p':0.5, 'goods.H.theta':100, 'goods.H.sigma':
20}). count(). Это найдет правильное количество документов...
-
Реструктурируйте свои данные → если вы посмотрите на MongoDB: порядок индексов и порядок запросов должны совпадать? вы можете индексировать на p, sigma, theta, так что когда в запросе любой порядок условий предоставит правильный результат. В моих кратких тестах (я не эксперт) я не смог индексировать таким образом, который производит тот же эффект с вашей текущей структурой.
Ответ 3
Я думаю, что ваша проблема упоминается в mongodb doc:
Поле должно точно соответствовать субдоку, включая порядок....
посмотрите здесь.
Пример с суб-документом.
Поля в суб-документе должны быть в том же порядке, что и в запросе, который нужно сопоставить.
Ответ 4
Я думаю, что вы ищете $где оператор.
Это работает в Node:
var myCursor = coll.find({$where: function () {return obj.goods.H == d1}});
myCursor.count(function (err, myCount) {console.log(myCount)});
В Python я считаю, что вам нужно передать объект кода BSON.
Документация предупреждает, что оператор $where следует использовать как последнее средство, поскольку он имеет ограничение производительности и не может использовать индексы.
Похоже, что может быть целесообразно установить порядок подчиненных свойств и обеспечить его, если это возможно, при вставке или в качестве почтового процесса.