MongoDB Query Help - запрос значений любого ключа в под-объекте
Я хочу выполнить запрос в этой коллекции, чтобы определить, какие документы имеют какие-либо ключи в вещах, которые соответствуют определенному значению. Возможно ли это?
У меня есть набор документов вроде:
{
"things": {
"thing1": "red",
"thing2": "blue",
"thing3": "green"
}
}
EDIT: для краткости
Ответы
Ответ 1
Я бы предложил изменение схемы, чтобы вы могли действительно делать разумные запросы в MongoDB.
From:
{
"userId": "12347",
"settings": {
"SettingA": "blue",
"SettingB": "blue",
"SettingC": "green"
}
}
в
{
"userId": "12347",
"settings": [
{ name: "SettingA", value: "blue" },
{ name: "SettingB", value: "blue" },
{ name: "SettingC", value: "green" }
]
}
Затем вы можете индексировать на "settings.value"
и делать запрос типа:
db.settings.ensureIndex({ "settings.value" : 1})
db.settings.find({ "settings.value" : "blue" })
Изменение действительно просто..., поскольку оно перемещает имя и значение параметра в полностью индексируемые поля и сохраняет список настроек в виде массива.
Если вы не можете изменить схему, вы можете попробовать @JohnnyHK , но будьте осторожны что это в основном худший случай с точки зрения производительности, и он не будет эффективно работать с индексами.
Ответ 2
Если вы не знаете, какими будут клавиши, и вам нужно, чтобы это было интерактивным, тогда вам нужно будет использовать (как известно, вызов производительности) $where
такой оператор (в оболочке):
db.test.find({$where: function() {
for (var field in this.settings) {
if (this.settings[field] == "red") return true;
}
return false;
}})
Если у вас большая коллекция, это может быть слишком медленным для ваших целей, но это ваш единственный вариант, если ваш набор ключей неизвестен.
Ответ 3
К сожалению, ни один из предыдущих ответов не касается того факта, что mongo может содержать вложенные значения в массивах или вложенных объектах.
ЭТО ПРАВИЛЬНЫЙ ЗАПРОС:
{$where: function() {
var deepIterate = function (obj, value) {
for (var field in obj) {
if (obj[field] == value){
return true;
}
var found = false;
if ( typeof obj[field] === 'object') {
found = deepIterate(obj[field], value)
if (found) { return true; }
}
}
return false;
};
return deepIterate(this, "573c79aef4ef4b9a9523028f")
}}
Так как вызов typeof по массиву или вложенному объекту будет возвращать "объект", это означает, что запрос будет перебирать все вложенные элементы и будет проходить через все из них до тех пор, пока не будет найден ключ со значением.
Вы можете проверить предыдущие ответы с вложенным значением, и результаты будут далеки от желаний.
Строгое отображение всего объекта - это удар по производительности, поскольку он должен последовательно перебирать все сектора памяти, пытаясь их сопоставить. И создает копию объекта в виде строки в памяти RAM (обе неэффективны, поскольку запрос использует больше ram и slow, так как в контексте функции уже есть загруженный объект).
Сам запрос может работать с objectId, string, int и любым базовым типом javascript, который вы хотите.