sql >> Database teknologi >  >> NoSQL >> MongoDB

Forespørg og filtrer nøglenavne i stedet for værdier i MongoDB

Du kan gøre det ved at bruge mapReduce :

For at få kun feltnavnene på rodniveau:

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

Dette vil udsende noget som dette:

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

For at få feltnavne og en hvilken som helst eller alle (hele dokumentet) dens værdier:

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

Dette vil udsende noget som dette:

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

For at få feltnavne i underdokumenter (uden sti):

For at gøre det skal du bruge 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])
    });
}});

Og skift dit kort til:

function () {
    getFields(this);
}

Kør nu db.loadServerScripts() for at indlæse dem.

For at få feltnavne i underdokumenter (med sti):

Den tidligere version vil bare returnere feltnavne, ikke hele stien for at få dem, hvilket du skal bruge, hvis det du vil gøre er at omdøbe disse nøgler. Sådan får du stien:

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

Og skift dit kort til:

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

Sådan ekskluderer du overlappende sti-matches:

Bemærk, at hvis du har et felt fkfoo.fkbar , vil det returnere fkfoo og fkfoo.fkbar . Hvis du ikke vil have overlappende sti-matches, så:

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

Vender tilbage til dit spørgsmål og omdøber disse felter:

Med denne sidste mulighed får du alle de stier, der inkluderer nøgler, der starter med fk , så du kan bruge $rename for det.

Dog $rename virker ikke for dem, der indeholder arrays, så for dem kan du bruge forEach at lave opdateringen. Se MongoDB omdøb databasefeltet i matrix

Ydeevnenote:

MapReduce er ikke særlig hurtig tænkt, så du vil måske specificere { out: "fk_fields"} at udlæse resultaterne i en ny samling kaldet fk_fields og forespørg efter disse resultater senere, men det vil afhænge af din use case.

Mulige optimeringer til specifikke tilfælde (konsistent skema):

Bemærk også, at hvis du ved, at skemaet for dine dokumenter altid er det samme, så skal du bare tjekke et af dem for at få dets felter, så du kan gøre det ved at tilføje limit: 1 til options-objektet eller blot at hente ét dokument med findOne og læse dens felter på applikationsniveauet.



  1. Sådan indstilles docker mongo datavolumen

  2. Hvordan implementerer man oAuth2 sammen med JWT-godkendelse i spring boot?

  3. Sådan bruger du $regex inde i $eller som et aggregeringsudtryk

  4. Hvad er JavaScript-motoren, der kører mongoDB shell?