Как найти имя поля MongoDB на произвольной глубине
я импортировал какие-то неаккуратные XML-данные в базу данных Mongo. Каждый документ имеет вложенные вложенные документы глубиной около 5-10. Я хочу найти() документов, имеющих определенное значение определенного поля, где поле может появиться на любой глубине в подразделе Документы (и может появляться несколько раз).
в настоящее время я вытаскиваю каждый документ в Python, а затем ищу этот словарь, но было бы неплохо, если бы я мог указать прототип фильтра, где база данных будет возвращать только документы, которые имеют определенное значение имени поля где-то в их содержимом.
вот пример документа:
{
"foo": 1,
"bar": 2,
"find-this": "Yes!",
"stuff": {
"baz": 3,
"gobble": [
"wibble",
"wobble",
{
"all-fall-down": 4,
"find-this": "please find me"
}
],
"plugh": {
"plove": {
"find-this": "Here too!"
}
}
}
}
Итак, я хотел бы найти документы, которые имеют поле "Найти-это", и (если возможно) иметь возможность найти документы, которые имеют определенное значение поля "найти-это".
2 ответов
вы правы в определенном утверждении документа BSON не является XML-документом. Поскольку XML загружается в древовидную структуру, состоящую из "узлов", поиск по ключу arbitary довольно прост.
документ MonoDB не так прост в обработке, и это "база данных" во многих отношениях, поэтому обычно ожидается, что он будет иметь определенную "однородность" местоположений данных, чтобы упростить как "индекс", так и поиск.
тем не менее, это можно сделать. Но конечно, это означает рекурсивный процесс, выполняемый на сервере, и это означает обработку JavaScript с помощью $where
.
в качестве основного примера оболочки, но общие function
- это просто строка параметр $where
оператор везде:
db.collection.find(
function () {
var findKey = "find-this",
findVal = "please find me";
function inspectObj(doc) {
return Object.keys(doc).some(function(key) {
if ( typeof(doc[key]) == "object" ) {
return inspectObj(doc[key]);
} else {
return ( key == findKey && doc[key] == findVal );
}
});
}
return inspectObj(this);
}
)
таким образом, в основном, проверьте ключи, присутствующие в объекте, чтобы увидеть, соответствуют ли они желаемому "имени Поля" и содержимому. Если один из этих ключей является "объектом", то рекурсия в функция и проверяет снова.
JavaScript .some()
убеждается что" первое " найденное спичка возвратит от функции поиска давая true
результат и возвращением объекта, где этот "ключ/значение" присутствовал на некоторой глубине.
отметим, что $where
по существу означает обход всей коллекции, если нет другого допустимого фильтра запросов, который может быть применен к "индексу" в коллекции.
так используйте с осторожностью, или не на всех и просто работать с Re-structring данные в более конструктивной форме.
но это даст вам ваш матч.
вот один пример, который я использую для рекурсивного поиска ключевого значения в любом месте структуры документа:
db.getCollection('myCollection').find({
"$where" : function(){
var searchKey = 'find-this';
var searchValue = 'please find me';
return searchInObj(obj);
function searchInObj(obj){
for(var k in obj){
if(typeof obj[k] == 'object' && obj[k] !== null){
if(searchInObj(obj[k])){
return true;
}
} else {
if(k == searchKey && obj[k] == searchValue){
return true;
}
}
}
return false;
}
}
})