MongoDB
 sql >> Teknologi Basis Data >  >> NoSQL >> MongoDB

Kueri dan filter nama kunci alih-alih nilai di MongoDB

Anda dapat melakukannya menggunakan mapReduce :

Untuk mendapatkan nama bidang saja di tingkat akar:

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

Ini akan menampilkan sesuatu seperti ini:

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

Untuk mendapatkan nama bidang dan salah satu atau semua (seluruh dokumen) nilainya:

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

Ini akan menampilkan sesuatu seperti ini:

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

Untuk mendapatkan nama bidang dalam subdokumen (tanpa jalur):

Untuk melakukannya, Anda harus menggunakan 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])
    });
}});

Dan ubah peta Anda menjadi:

function () {
    getFields(this);
}

Sekarang jalankan db.loadServerScripts() untuk memuatnya.

Untuk mendapatkan nama bidang di subdokumen (dengan jalur):

Versi sebelumnya hanya akan mengembalikan nama bidang, bukan seluruh jalur untuk mendapatkannya, yang akan Anda perlukan jika yang ingin Anda lakukan adalah mengganti nama kunci tersebut. Untuk mendapatkan jalur:

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

Dan ubah peta Anda menjadi:

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

Untuk mengecualikan kecocokan jalur yang tumpang tindih:

Perhatikan bahwa jika Anda memiliki bidang fkfoo.fkbar , itu akan mengembalikan fkfoo dan fkfoo.fkbar . Jika Anda tidak ingin kecocokan jalur yang tumpang tindih, maka:

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

Kembali ke pertanyaan Anda, mengganti nama bidang tersebut:

Dengan opsi terakhir ini, Anda mendapatkan semua jalur yang menyertakan kunci yang dimulai dengan fk , sehingga Anda dapat menggunakan $rename untuk itu.

Namun, $rename tidak berfungsi untuk yang berisi array, jadi bagi yang Anda dapat menggunakan forEach untuk melakukan pembaruan. Lihat MongoDB mengganti nama bidang basis data dalam larik

Catatan kinerja:

MapReduce tidak terlalu dipikirkan dengan cepat, jadi Anda mungkin ingin menentukan { out: "fk_fields"} untuk menampilkan hasilnya ke dalam koleksi baru yang disebut fk_fields dan kueri hasil tersebut nanti, tetapi itu akan bergantung pada kasus penggunaan Anda.

Pengoptimalan yang memungkinkan untuk kasus tertentu (skema yang konsisten):

Juga, perhatikan bahwa jika Anda tahu bahwa skema dokumen Anda selalu sama, maka Anda hanya perlu memeriksa salah satunya untuk mendapatkan bidangnya, sehingga Anda dapat melakukannya dengan menambahkan limit: 1 ke objek opsi atau hanya mengambil satu dokumen dengan findOne dan membaca bidangnya di tingkat aplikasi.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. pymongo update_one(), upsert=True tanpa menggunakan $ operator

  2. cara memperbarui banyak dokumen dengan nilai berbeda

  3. Cara membuat pengguna di MongoDB

  4. Buat ISODate dengan pyMongo

  5. Hitung nilai rata-rata dokumen mongodb