Как найти имя поля 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;
        }       
    }    
})