Поиск значения любого поля в MongoDB без явного называния его
Я просмотрел документацию MongoDB и перешел к этому вопросу, но не смог найти подходящего ответа. Итак, вот что я ищу.
Предположим, у меня есть коллекция с такими элементами:
{
"foo" : "bar",
"test" : "test",
"key" : "value",
}
Я бы хотел найти элемент, выполнив поиск во всех (возможно, за исключением конечного числа;-)) полей. Другими словами: Если задан запрос, я НЕ знаю, в каком поле должен быть найден запрос.
В моем мышлении что-то вроде этого
db.things.find({_ANY_ : "bar"})
даст мне примерный элемент.
Благодарим вас за помощь.
Ответы
Ответ 1
чтобы выполнить текстовый поиск по всем полям, сначала необходимо создать текстовый индекс для всех полей.
в качестве документации mongodb указывает:" Чтобы разрешить текстовый поиск во всех полях с содержимым строки, используйте спецификатор подстановки ($ **), чтобы индексировать все поля, которые содержат содержимое строки.
если вы работаете внутри оболочки mongo (которую вы выполняете из командной строки, вызывая "mongo" ), вы можете сделать это с помощью этой команды, где "коллекция" - это имя коллекции в db, которую вы хотите для использования.
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 в текстовом поиске здесь
Ответ 2
Этот ответ на похожий вопрос имеет ваше решение, которое я повторю здесь для полноты. Вы можете использовать оператор $where
для запуска произвольного JavaScript на серверах MongoDB с оговоркой, что это будет намного медленнее, чем почти любой другой тип запроса. Для вашего примера это будет:
db.things.find({$where: function() {
for (var key in this) {
if (this[key] === "bar") {
return true;
}
}
return false;
}});
Ответ 3
Это невозможно без индивидуальной проверки документов на стороне приложения или при выполнении кода на стороне сервера. Рассмотрите возможность изменения вашей схемы:
{params:[{field:"foo", value:"bar"}, {field:"test", value:"test"}, {field:"key", value:"value"}]}
Это, очевидно, имеет некоторые недостатки (производительность и политическая схема в основном), но позволят вам:
db.things.find({'params.value':"bar"})
Ответ 4
К сожалению, ни один из предыдущих ответов не касается того факта, что 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, так как в контексте функции уже есть загруженный объект)
Ответ 5
Вы можете сделать это с помощью рекурсивной функции:
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');
Ответ 6
Используя $, где совпадает с выполнением полного сканирования таблицы и не может использовать индексы. Я также не мог заставить его работать, однако я нашел, что это сработало (это также эквивалентно полному сканированию таблицы):
db.collection.find().forEach(function(doc){
for (var key in doc) {
if ( /needle/.test(doc[key]) )
printjson(doc);
}
});
где /needle/
- регулярное выражение для нахождения в значении doc[key]
Ответ 7
Для выполнения текстового поиска вам необходимо создать текстовые индексы для своей коллекции.
Для получения дополнительной информации см. Документацию по mongo: индексирует текст
Ответ 8
{
"foo" : "bar",
"test" : "test",
"key" : "value",
}
db.collection_name.find({'foo':"bar"})