Подтвердить что ты не робот

MongoDB Query Help - запрос значений любого ключа в под-объекте

Я хочу выполнить запрос в этой коллекции, чтобы определить, какие документы имеют какие-либо ключи в вещах, которые соответствуют определенному значению. Возможно ли это?

У меня есть набор документов вроде:

{
    "things": {
        "thing1": "red",
        "thing2": "blue",
        "thing3": "green"
    }
}

EDIT: для краткости

4b9b3361

Ответ 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, который вы хотите.