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
, ognumber
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);
}
}
Så 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.