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

Как да съхранявате подреден набор от документи в MongoDB, без да използвате ограничена колекция

Въз основа на вашето изискване един от подходите може да бъде да проектирате вашата схема по такъв начин, че всеки документ да има възможността да съдържа повече от един документ и сам по себе си да действа като затворен контейнер .

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

Всеки документ в колекцията ще действа като затворен контейнер и документите ще бъдат съхранени като масив в doc поле. doc полето, което е масив, ще поддържа реда на вмъкване. Можете да ограничите броя на документите до n . Така че _id полето на всеки контейнерен документ ще бъде инкрементално с n , указващ броя на документите, които контейнерният документ може да побере.

Като правите това, вие избягвате добавяне на extra fields към документа, extra indices , unnecessary sorts .

Вмъкване на първия запис

когато колекцията е празна.

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

Вмъкване на последващи записи

  • Идентифицирайте _id на последния контейнерен документ и number на документите, които притежава.
  • Ако броят документи, които съдържа, е по-малък от n , след което актуализирайте документът на контейнера с новия документ, в противен случай създайте нов контейнерен документ.

Кажете, че всеки container document може да побере 5 най-много документи и искаме да вмъкнем нов документ.

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

Имайте предвид, че aggregation , работи от страна на сървъра и е много ефективен, имайте предвид също, че aggregation ще ви върне документ вместо курсор във версии previous to 2.6 . Така че ще трябва да промените горния код, за да избирате само от един документ, вместо да повтаряте курсора.

Вмъкване на нов документ между документите

Сега, ако искате да вмъкнете нов документ между документите 1 и 2 , знаем, че документът трябва да попадне в контейнера с _id=0 и трябва да се постави във second позиция в doc масив от този контейнер.

така че ние използваме $each и $position оператори за вмъкване в определени позиции.

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

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

Обработка на поток

Сега трябва да се погрижим за overflowing на документи във всеки container , да речем, че вмъкваме нов документ между тях, в контейнер с _id=0 . Ако контейнерът вече има 5 документи, трябва да move the last document to the next container и правете това, докато всички контейнери поберат документи в рамките на техния капацитет, ако е необходимо, най-накрая трябва да създадем контейнер, който да побере препълващите документи.

Тази сложна оперия да се извърши от сървърната страна . За да се справим с това, можем да създадем скрипт като този по-долу и register то с 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);
}
}

Така че after every insertion in between , можем да извикаме тази function чрез предаване на идентификатора на контейнера, handleOverFlow(containerId) .

Извличане на всички записи по ред

Просто използвайте $unwind оператор в aggregate pipeline .

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

Пренареждане на документи

Можете да съхранявате всеки документ в затворен контейнер с поле „_id“:

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

Вземете масива „doc“ на затворения контейнер, в който искате да пренаредите елементи.

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

Актуализирайте техните идентификатори, така че след сортиране редът на елемента да се промени.

Сортирайте масива въз основа на техните _ids.

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

актуализирайте затворения контейнер обратно, с новия масив на документи.

Но отново всичко се свежда до това кой подход е осъществим и отговаря най-добре на вашите изисквания.

Стигаме до вашите въпроси:

Документи като масиви.

използвайте $each и $position оператори в db.collection.update() функция, както е описано в моя отговор.

да Това би повлияло на производителността, освен ако колекцията има много по-малко данни.

да С ограничените колекции може да загубите данни.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Express Mongoose Model.find() връща undefined

  2. Намиране на всички записи, съдържащи дадено подполе в mongodb

  3. Схема за дата Mongoose

  4. Изключение за сериализация на Scala със стойност на изброяване

  5. Изпълнение на mongodb на ubuntu 16.04 LTS