sql >> Databáze >  >> NoSQL >> MongoDB

Dotazujte se a filtrujte názvy klíčů namísto hodnot v MongoDB

Můžete to udělat pomocí mapReduce :

Chcete-li získat pouze názvy polí na kořenové úrovni:

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 }});

Výsledkem bude něco takového:

{
    "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
}

Chcete-li získat názvy polí a všechny nebo všechny (celý dokument) jejich hodnoty:

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 }});

Výsledkem bude něco takového:

{
    "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
}

Získání názvů polí ve vnořených dokumentech (bez cesty):

K tomu budete muset použít 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])
    });
}});

A změňte mapu na:

function () {
    getFields(this);
}

Nyní spusťte db.loadServerScripts() k jejich načtení.

Získání názvů polí ve vnořených dokumentech (s cestou):

Předchozí verze vrátí pouze názvy polí, nikoli celou cestu k jejich získání, což budete potřebovat, pokud chcete tyto klíče přejmenovat. Chcete-li získat cestu:

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 + '.')
    });
}});

A změňte mapu na:

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

Vyloučení překrývajících se shod cest:

Všimněte si, že pokud máte pole fkfoo.fkbar , vrátí fkfoo a fkfoo.fkbar . Pokud nechcete, aby se cesty překrývaly, pak:

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);
    });
}});

Vraťme se k vaší otázce a přejmenujte tato pole:

S touto poslední možností získáte všechny cesty, které zahrnují klíče začínající fk , takže můžete použít $rename za to.

Nicméně $rename nefunguje pro ty, které obsahují pole, takže pro ty můžete použít forEach provést aktualizaci. Viz Přejmenování pole databáze MongoDB v poli

Poznámka k výkonu:

MapReduce není příliš rychlý, takže možná budete chtít zadat { out: "fk_fields"} pro výstup výsledků do nové kolekce nazvané fk_fields a dotazujte se na tyto výsledky později, ale to bude záviset na vašem případu použití.

Možné optimalizace pro konkrétní případy (konzistentní schéma):

Také si uvědomte, že pokud víte, že schéma vašich dokumentů je vždy stejné, pak stačí zaškrtnout jeden z nich, abyste získali jeho pole, takže to můžete udělat přidáním limit: 1 k objektu options nebo jen načtením jednoho dokumentu pomocí findOne a čtení jeho polí na aplikační úrovni.



  1. Konfigurace oauth2-server-laravel pomocí laravel-mongodb

  2. Nastavte vlastní převodníky v Spring Data Mongo

  3. Mongoidní stejné typy vložených dokumentů pro různá pole

  4. Podpora WSO2 DSS pro mongodb 3.x.x