MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Имена на ключове за заявки и филтри вместо стойности в MongoDB

Можете да направите това с помощта на mapReduce :

За да получите само имената на полетата на основно ниво:

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

Това ще изведе нещо подобно:

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

За да получите имена на полета и някои или всички (целия документ) стойности:

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

Това ще изведе нещо подобно:

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

За да получите имена на полета в поддокументи (без път):

За да направите това, ще трябва да използвате 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])
    });
}});

И променете картата си на:

function () {
    getFields(this);
}

Сега стартирайте db.loadServerScripts() за да ги заредите.

За да получите имена на полета в поддокументи (с път):

Предишната версия просто ще върне имена на полета, а не целия път, за да ги получите, което ще ви трябва, ако това, което искате да направите, е да преименувате тези ключове. За да получите пътя:

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

И променете картата си на:

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

За да изключите съвпадения на припокриващи се пътища:

Имайте предвид, че ако имате поле fkfoo.fkbar , ще върне fkfoo и fkfoo.fkbar . Ако не искате съвпадения на припокриващи се пътища, тогава:

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

Връщайки се към вашия въпрос, преименуване на тези полета:

С тази последна опция получавате всички пътища, които включват ключове, които започват с fk , така че можете да използвате $rename за това.

Въпреки това, $rename не работи за тези, които съдържат масиви, така че за тези можете да използвате forEach за да направите актуализацията. Вижте MongoDB поле за преименуване на база данни в масива

Бележка за ефективността:

MapReduce не се мисли особено бързо, така че може да искате да посочите { out: "fk_fields"} за извеждане на резултатите в нова колекция, наречена fk_fields и потърсете тези резултати по-късно, но това ще зависи от вашия случай на употреба.

Възможни оптимизации за конкретни случаи (последователна схема):

Освен това имайте предвид, че ако знаете, че схемата на вашите документи винаги е една и съща, тогава просто трябва да поставите отметка на един от тях, за да получите неговите полета, така че можете да направите това, като добавите limit: 1 към обекта с опции или просто извличане на един документ с findOne и четене на неговите полета на ниво приложение.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Използвайки драйвера mongo C#, как да сериализирате масив от потребителски обект, за да го съхраните?

  2. Как да използвате $regex в $or като агрегиращ израз

  3. Как да предотвратите добавянето на множество документи към базата данни на mongodb

  4. Как написах приложение за най-висока класация за една седмица с Realm и SwiftUI

  5. Mongodb - все още ли са значителни проблемите с надеждността?