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

Sådan gemmer du et bestilt sæt dokumenter i MongoDB uden at bruge en begrænset samling

Baseret på dit krav kan en af ​​tilgangene være at designe dit skema på en sådan måde, at hvert dokument har kapaciteten at opbevare mere end ét dokument og i sig selv fungere som en beholder med låg .

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

Hvert dokument i samlingen fungerer som en beholder med låg , og dokumenterne vil blive gemt som array i doc Mark. doc feltet, der er en matrix, vil bevare rækkefølgen af ​​indsættelse. Du kan begrænse antallet af dokumenter til n . Så _id felt for hvert containerdokument vil være trinvist med n , der angiver antallet af dokumenter et containerdokument kan indeholde.

Ved at gøre disse undgår tilføjelse af extra fields til dokumentet, extra indices , unnecessary sorts .

Indsættelse af den allerførste post

når samlingen er tom.

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

Indsættelse af efterfølgende poster

  • Identificer det sidste containerdokuments _id , og number af dokumenter, den har.
  • Hvis antallet af dokumenter, den indeholder, er mindre end n , og derefter opdater containerdokumentet med det nye dokument, ellers opret et nyt containerdokument.

Sig, at hvert container document kan indeholde 5 dokumenter højst, og vi ønsker at indsætte et nyt dokument.

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

Bemærk, at aggregation , kører på serversiden og er meget effektiv, bemærk også at aggregation ville returnere dig et dokument i stedet for en markør i versioner previous to 2.6 . Så du bliver nødt til at ændre ovenstående kode for kun at vælge fra et enkelt dokument i stedet for at gentage en markør.

Indsættelse af et nyt dokument mellem dokumenter

Hvis du nu vil indsætte et nyt dokument mellem dokumenter 1 og 2 , vi ved, at dokumentet skal falde inde i containeren med _id=0 og skal placeres i second position i doc array af denne container.

så vi gør brug af $each og $position operatører til indsættelse i specifikke positioner.

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

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

Håndtering af overflow

Nu skal vi sørge for, at dokumenter overflowing i hver container , sig, at vi indsætter et nyt dokument imellem, i container med _id=0 . Hvis containeren allerede har 5 dokumenter, skal vi move the last document to the next container og gør det, indtil alle containerne rummer dokumenter inden for deres kapacitet, hvis det kræves, skal vi endelig oprette en container til at opbevare de overfyldte dokumenter.

Denne komplekse operation bør gøres på serversiden . For at håndtere dette kan vi oprette et script som det nedenfor og register det med 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 , kan vi aktivere denne function ved at sende container-id'et, handleOverFlow(containerId) .

Henter alle posterne i rækkefølge

Bare brug $unwind operatør i aggregate pipeline .

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

Genbestilling af dokumenter

Du kan gemme hvert dokument i en lukket beholder med et "_id"-felt:

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

Få fat i "doc"-arrayet i den lukkede beholder, som du vil genbestille varer fra.

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

Opdater deres id'er, så rækkefølgen af ​​varen efter sortering ændres.

Sorter arrayet ud fra deres _id'er.

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

opdater den lukkede container tilbage med det nye doc-array.

Men igen, alt koger ned til, hvilken tilgang der er gennemførlig og passer bedst til dit krav.

Kommer til dine spørgsmål:

Dokumenter som arrays.

brug $each og $position operatorer i db.collection.update() fungerer som afbildet i mit svar.

Ja. Det vil påvirke ydeevnen, medmindre samlingen har meget færre data.

Ja. Med begrænsede samlinger kan du miste data.



  1. Pymongo - ValueError:NaTType understøtter ikke utcoffset ved brug af insert_many

  2. Hvordan får man den aktuelle database, som Mongoid skriver til, programmæssigt?

  3. Symfony2 + Skal bruge det regulære udtryk i doktrinens mongodb ODM for at kontrollere tjek uden store og små bogstaver

  4. Aggregation i kolbe-mongomotor