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

Cara menyimpan kumpulan dokumen yang dipesan di MongoDB tanpa menggunakan koleksi yang dibatasi

Berdasarkan kebutuhan Anda, salah satu pendekatannya adalah merancang skema Anda, sedemikian rupa sehingga setiap dokumen memiliki kemampuan untuk menampung lebih dari satu dokumen dan dengan sendirinya bertindak sebagai wadah tertutup .

{
  "_id":Number,
  "doc":Array
}

Setiap dokumen dalam koleksi akan bertindak sebagai wadah tertutup , dan dokumen akan disimpan sebagai array di doc bidang. doc bidang menjadi array, akan mempertahankan urutan penyisipan. Anda dapat membatasi jumlah dokumen menjadi n . Jadi _id bidang setiap dokumen kontainer akan bertambah dengan n , menunjukkan jumlah dokumen yang dapat disimpan oleh dokumen kontainer.

Dengan melakukan ini, Anda menghindari menambahkan extra fields ke dokumen, extra indices , unnecessary sorts .

Memasukkan rekaman pertama

yaitu saat koleksi kosong.

var record = {"name" : "first"};
db.col.insert({"_id":0,"doc":[record]});

Memasukkan catatan berikutnya

  • Identifikasi _id dokumen penampung terakhir , dan number dokumen yang dimilikinya.
  • Jika jumlah dokumen yang disimpan kurang dari n , lalu perbarui dokumen penampung dengan dokumen baru, jika tidak buat dokumen kontainer baru.

Katakanlah, bahwa setiap container document dapat menahan 5 dokumen paling banyak, dan kami ingin memasukkan dokumen baru.

var record = {"name" : "newlyAdded"};

// using aggregation, get the _id of the last inserted container, and the 
// number of record it currently holds.
db.col.aggregate( [ {
    $group : {
        "_id" : null,
        "max" : {
            $max : "$_id"
        },
        "lastDocSize" : {
            $last : "$doc"
        }
    }
}, {
    $project : {
        "currentMaxId" : "$max",
        "capSize" : {
            $size : "$lastDocSize"
        },
        "_id" : 0
    }
// once obtained, check if you need to update the last container or 
// create a new container and insert the document in it.
} ]).forEach( function(check) {
    if (check.capSize < 5) {
        print("updating");
        // UPDATE
        db.col.update( {
            "_id" : check.currentMaxId
        }, {
            $push : {
                "doc" : record
            }
        });
    } else {
        print("inserting");
        //insert
        db.col.insert( {
            "_id" : check.currentMaxId + 5,
            "doc" : [ record ]
        });
    }
})

Perhatikan bahwa aggregation , berjalan di sisi server dan sangat efisien, perhatikan juga bahwa aggregation akan mengembalikan dokumen daripada kursor di versi previous to 2.6 . Jadi, Anda perlu memodifikasi kode di atas untuk hanya memilih dari satu dokumen daripada mengulangi kursor.

Memasukkan dokumen baru di antara dokumen

Sekarang, jika Anda ingin menyisipkan dokumen baru di antara dokumen 1 dan 2 , kita tahu bahwa dokumen harus berada di dalam wadah dengan _id=0 dan harus ditempatkan di second posisi di doc array wadah itu.

jadi, kami menggunakan $each dan $position operator untuk dimasukkan ke dalam posisi tertentu.

var record = {"name" : "insertInMiddle"};

db.col.update(
{
    "_id" : 0
}, {
    $push : {
        "doc" : {
            $each : [record],
            $position : 1
        }
    }
}
);

Penanganan Arus Lebih

Sekarang, kita perlu mengurus dokumen overflowing di setiap container , katakanlah kita menyisipkan dokumen baru di antaranya, dalam wadah dengan _id=0 . Jika wadah sudah memiliki 5 dokumen, kita perlu move the last document to the next container dan lakukan sampai semua kontainer menampung dokumen sesuai kapasitasnya, jika diperlukan akhirnya kita perlu membuat kontainer untuk menampung dokumen yang meluap.

Operasi yang rumit ini harus dilakukan di sisi server . Untuk mengatasinya, kita bisa membuat script seperti di bawah ini dan register dengan mongodb.

db.system.js.save( {
    "_id" : "handleOverFlow",
    "value" : function handleOverFlow(id) {
        var currDocArr = db.col.find( {
            "_id" : id
        })[0].doc;
        print(currDocArr);
        var count = currDocArr.length;
        var nextColId = id + 5;
        // check if the collection size has exceeded
    if (count <= 5)
        return;
    else {
        // need to take the last doc and push it to the next capped 
    // container's array
    print("updating collection: " + id);
    var record = currDocArr.splice(currDocArr.length - 1, 1);
    // update the next collection
    db.col.update( {
        "_id" : nextColId
    }, {
        $push : {
            "doc" : {
                $each : record,
                $position : 0
            }
        }
    });
    // remove from original collection
    db.col.update( {
        "_id" : id
    }, {
        "doc" : currDocArr
    });
    // check overflow for the subsequent containers, recursively.
    handleOverFlow(nextColId);
}
}

Sehingga after every insertion in between , kita dapat memanggil function ini dengan meneruskan id wadah, handleOverFlow(containerId) .

Mengambil semua catatan secara berurutan

Cukup gunakan $unwind operator di aggregate pipeline .

db.col.aggregate([{$unwind:"$doc"},{$project:{"_id":0,"doc":1}}]);

Memesan Ulang Dokumen

Anda dapat menyimpan setiap dokumen dalam wadah tertutup dengan bidang "_id":

.."doc":[{"_id":0,","name":"xyz",...}..]..

Dapatkan larik "doc" dari wadah tertutup yang ingin Anda pesan ulang itemnya.

var docArray = db.col.find({"_id":0})[0];

Perbarui id mereka sehingga setelah mengurutkan urutan item akan berubah.

Urutkan array berdasarkan _id-nya.

docArray.sort( function(a, b) {
    return a._id - b._id;
});

perbarui wadah yang ditutup kembali, dengan larik dokumen baru.

Tetapi sekali lagi, semuanya bermuara pada pendekatan mana yang layak dan paling sesuai dengan kebutuhan Anda.

Datang ke pertanyaan Anda:

Dokumen sebagai Array.

gunakan $each dan $position operator di db.collection.update() berfungsi seperti yang digambarkan dalam jawaban saya.

Ya. Ini akan memengaruhi kinerja, kecuali jika koleksi memiliki data yang sangat sedikit.

Ya. Dengan Koleksi yang Dibatasi, Anda mungkin kehilangan data.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Agregat MongoDB berdasarkan bidang ada

  2. Mendapatkan kamus di dalam daftar dengan kunci di mongoDB (mongoengine)

  3. Bidang Asing dari $lookup bisa menjadi bidang dokumen bersarang?

  4. Dampak kinerja tipe data indeks di MongoDB?

  5. Dorong nilai ke dalam array database mongodb melalui (sails js) waterline