MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Zapytanie i filtrowanie nazw kluczy zamiast wartości w MongoDB

Możesz to zrobić za pomocą mapReduce :

Aby uzyskać tylko nazwy pól na poziomie głównym:

db.collection.mapReduce(function () {
    Object.keys(this).map(function(key) {
        if (key.match(/^fk/)) emit(key, null);

        // OR: key.indexOf("fk") === 0
    });
}, function(/* key, values */) {
    // No need for params or to return anything in the 
    // reduce, just pass an empty function.
}, { out: { inline: 1 }});

Spowoduje to wyświetlenie czegoś takiego:

{
    "results": [{
        "_id": "fkKey1",
        "value": null
    }, {
        "_id": "fkKey2",
        "value": null
    }, {
        "_id": "fkKey3",
        "value": null
    }],
    "timeMillis": W,
    "counts": {
        "input": X,
        "emit": Y,
        "reduce": Z,
        "output": 3
    },
    "ok" : 1
}

Aby uzyskać nazwy pól i dowolne lub wszystkie (cały dokument) ich wartości:

db.test.mapReduce(function () {
    var obj = this;

    Object.keys(this).map(function(key) {
        // With `obj[key]` you will get the value of the field as well.
        // You can change `obj[key]` for:
        //  - `obj` to return the whole document.
        //  - `obj._id` (or any other field) to return its value.

        if (key.match(/^fk/)) emit(key, obj[key]);
    });
}, function(key, values) {
    // We can't return values or an array directly yet:

    return { values: values };
}, { out: { inline: 1 }});

Spowoduje to wyświetlenie czegoś takiego:

{
    "results": [{
        "_id": "fkKey1",
        "value": {
            "values": [1, 4, 6]
        }
    }, {
        "_id": "fkKey2",
        "value": {
            "values": ["foo", "bar"]
        }
    }],
    "timeMillis": W,
    "counts": {
        "input": X,
        "emit": Y,
        "reduce": Z,
        "output": 2
    },
    "ok" : 1
}

Aby uzyskać nazwy pól w dokumentach podrzędnych (bez ścieżki):

Aby to zrobić, będziesz musiał użyć store JavaScript functions on the Server :

db.system.js.save({ _id: "hasChildren", value: function(obj) {
    return typeof obj === "object";
}});

db.system.js.save({ _id: "getFields", value: function(doc) {
    Object.keys(doc).map(function(key) {
        if (key.match(/^fk/)) emit(key, null);

        if (hasChildren(doc[key])) getFields(doc[key])
    });
}});

I zmień swoją mapę na:

function () {
    getFields(this);
}

Teraz uruchom db.loadServerScripts() aby je załadować.

Aby uzyskać nazwy pól w dokumentach podrzędnych (ze ścieżką):

Poprzednia wersja zwróci tylko nazwy pól, a nie całą ścieżkę do ich uzyskania, co będzie potrzebne, jeśli chcesz zmienić nazwy tych kluczy. Aby uzyskać ścieżkę:

db.system.js.save({ _id: "getFields", value: function(doc, prefix) {
    Object.keys(doc).map(function(key) {
        if (key.match(/^fk/)) emit(prefix + key, null);

        if (hasChildren(doc[key]))
            getFields(doc[key], prefix + key + '.')
    });
}});

I zmień swoją mapę na:

function () {
    getFields(this, '');
}

Aby wykluczyć nakładające się dopasowania ścieżek:

Zauważ, że jeśli masz pole fkfoo.fkbar , zwróci fkfoo i fkfoo.fkbar . Jeśli nie chcesz, aby pasujące ścieżki pokrywały się, to:

db.system.js.save({ _id: "getFields", value: function(doc, prefix) {
    Object.keys(doc).map(function(key) {
        if (hasChildren(doc[key]))
            getFields(doc[key], prefix + key + '.')
        else if (key.match(/^fk/)) emit(prefix + key, null);
    });
}});

Wracając do pytania, zmieniając nazwy tych pól:

Dzięki tej ostatniej opcji otrzymujesz wszystkie ścieżki zawierające klucze zaczynające się od fk , więc możesz użyć $rename za to.

Jednak $rename nie działa dla tych, które zawierają tablice, więc dla tych możesz użyć forEach zrobić aktualizację. Zobacz Pole bazy danych MongoDB zmiany nazwy w tablicy

Uwaga dotycząca wydajności:

MapReduce nie jest szczególnie szybki, więc możesz chcieć określić { out: "fk_fields"} aby wyprowadzić wyniki do nowej kolekcji o nazwie fk_fields i przeszukuj te wyniki później, ale będzie to zależeć od przypadku użycia.

Możliwe optymalizacje dla konkretnych przypadków (spójny schemat):

Pamiętaj też, że jeśli wiesz, że schemat Twoich dokumentów jest zawsze taki sam, wystarczy zaznaczyć jeden z nich, aby uzyskać jego pola, więc możesz to zrobić, dodając limit: 1 do obiektu opcji lub po prostu pobranie jednego dokumentu za pomocą findOne i odczytywanie jego pól na poziomie aplikacji.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB $addField i $indexOfArray w danych wiosennych

  2. Jaki jest odpowiednik findOne używającej .aggregate w Mongodb?

  3. Błąd podczas importu mongo

  4. Jak zintegrować MongoDB z Solr?

  5. Mongo aktualizacja poddokumentów