Поиск значения любого поля в MongoDB без явного присвоения ему имени - PullRequest
48 голосов
/ 22 июля 2011

Я просмотрел документацию MongoDB и погуглил этот вопрос, но не смог найти подходящий ответ. Итак, вот что я ищу. Предположим, у меня есть коллекция с такими элементами:

{
   "foo" : "bar",
   "test" : "test",
   "key" : "value",
}

Чего я хотел бы добиться, так это найти элемент путем поиска во всех (возможно, за исключением конечного числа ;-)) полях. Другими словами: учитывая запрос, я НЕ знаю, в каком поле должен быть найден запрос.

В моих мыслях что-то вроде этого

db.things.find({_ANY_ : "bar"}) 

даст мне пример элемента.

Спасибо за вашу помощь.

Ответы [ 8 ]

28 голосов
/ 07 марта 2016

Чтобы выполнить текстовый поиск по всем полям, сначала необходимо создать текстовый индекс по всем полям.

как указано в документации mongodb : «Чтобы разрешить текстовый поиск во всех полях со строковым содержимым, используйте спецификатор подстановочных знаков ($ **) для индексации всех полей, содержащих строковое содержимое».

если вы работаете внутри оболочки mongo (которую вы выполняете из командной строки, вызывая 'mongo'), то вы можете сделать это с помощью этой команды, где 'collection' - это имя коллекции вБД, которую вы хотите использовать.

db.collection.createIndex({ "$**": "text" },{ name: "TextIndex" })

второй объект, т. е. {name:"TextIndex"}, является необязательным ... вам на самом деле не нужно давать индексу имя, так какможет быть только один текстовый индекс для каждой коллекции (за раз ... вы можете удалить индексы и создать новые, если хотите).

как только вы создали текстовый индекс для всех полей, вы можете сделатьпростой текстовый поиск с использованием следующего объекта запроса: { $text : { $search: <your string> } }

поэтому, если вы пишете функцию javascript, вы можете сделать что-то вроде:

var cursor = db.collection(<collection_name>).find({ $text: { $search: <your string> } });

для получения дополнительной информации.информация о различных способах управления поиском, ссм. документацию mongodb по поиску текста здесь

25 голосов
/ 22 июля 2011

Это невозможно без индивидуальной проверки документов на стороне приложения или выполнения кода на стороне сервера.Подумайте об изменении схемы на:

{params:[{field:"foo", value:"bar"}, {field:"test", value:"test"}, {field:"key", value:"value"}]}

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

db.things.find({'params.value':"bar"})
24 голосов
/ 14 августа 2014

Этот ответ на аналогичный вопрос имеет ваше решение, которое я повторю здесь для полноты.Вы можете использовать оператор $where для запуска произвольного JavaScript на серверах MongoDB с оговоркой, что это будет намного медленнее, чем практически любой другой тип запроса.Для вашего примера это будет:

db.things.find({$where: function() {
    for (var key in this) {
        if (this[key] === "bar") {
            return true;
        }
        return false;
    }
}});
16 голосов
/ 14 июля 2016

К сожалению, ни один из предыдущих ответов не касается того факта, что 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 onмассив или вложенный объект будет возвращать «объект», это означает, что запрос будет повторяться по всем вложенным элементам и будет повторяться до тех пор, пока не будет найден ключ со значением.

Предыдущие ответы можно проверить с помощью вложенного элемента.значение и результаты будут далеки от желаемых.

Стрификация всего объекта гораздо менее производительна, поскольку он должен перебирать все сектора памяти один за другим, пытаясь сопоставить их.И создает копию объекта в виде строки в оперативной памяти (оба неэффективны, так как запрос использует больше оперативной памяти, и медленнее, поскольку в контексте функции уже есть загруженный объект)

3 голосов
/ 02 июня 2016

Использование $ где аналогично полному сканированию таблицы и не может использовать индексы.Я также не мог заставить его работать, однако я нашел, что это сработало (это также делает эквивалент полного сканирования таблицы):

db.collection.find().forEach(function(doc){
for (var key in doc) {
    if ( /needle/.test(doc[key]) )
        printjson(doc);
    }
});

, где /needle/ - это регулярное выражение, которое нужно найти в значенииdoc[key]

3 голосов
/ 09 июля 2013

Вы можете сделать это с помощью рекурсивной функции:

var recursiveSearch = function(query) {
    db.test_insert.find().forEach(function(items) {
        var i = 0;
        var recursiveFunc = function(itemsArray, itemKey) {
            var itemValue = itemsArray[itemKey];
            if(itemValue === query) { 
                printjson(items);
            }       

            if(typeof itemValue === "object") {
                Object.keys(itemValue).forEach(function(itemValueKey) {
                    recursiveFunc(itemValue, itemValueKey);
                });
            }
        };
        Object.keys(items).forEach(function(item){
            recursiveFunc(items, item);
        });
    });
};

recursiveSearch('your string');
2 голосов
/ 25 декабря 2013

Чтобы выполнить текстовый поиск, вы должны создать текстовые индексы для вашей коллекции. Для получения дополнительной информации см. Документацию по монго: индексный текст

0 голосов
/ 29 ноября 2016
{
   "foo" : "bar",
   "test" : "test",
   "key" : "value",
}

db.collection_name.find({'foo':"bar"})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...