sql >> Databasteknik >  >> NoSQL >> MongoDB

Varför har Mongoose både scheman och modeller?

EDIT: Även om detta har varit användbart för många människor, som nämnt i kommentarerna svarar det på "hur" snarare än varför. Tack och lov har frågans varför också besvarats på annat håll, med detta svar på en annan fråga. Detta har länkats i kommentarerna ett tag men jag inser att många kanske inte kommer så långt när de läser.

Ofta är det enklaste sättet att besvara den här typen av frågor med ett exempel. I det här fallet har någon redan gjort det åt mig :)

Ta en titt här:

http://rawberg.com/blog/nodejs/mongoose-orm-nested-models/

EDIT: Det ursprungliga inlägget (som nämnt i kommentarerna) verkar inte längre existera, så jag återger det nedan. Skulle den någonsin komma tillbaka, eller om den precis har flyttat, vänligen meddela mig.

Den ger en bra beskrivning av hur du använder scheman inom modeller i mongoose och varför du skulle vilja göra det, och visar dig också hur du pushar uppgifter via modellen medan schemat handlar om strukturen etc.

Original post:

Låt oss börja med ett enkelt exempel på att bädda in ett schema i en modell.

var TaskSchema = new Schema({
    name: String,
    priority: Number
});
 
TaskSchema.virtual('nameandpriority')
    .get( function () {
        return this.name + '(' + this.priority + ')';
    });
 
TaskSchema.method('isHighPriority', function() {
    if(this.priority === 1) {
        return true;
    } else {
        return false;
    }
}); 
 
var ListSchema = new Schema({
    name: String,
    tasks: [TaskSchema]
});
 
mongoose.model('List', ListSchema);
 
var List = mongoose.model('List');
 
var sampleList = new List({name:'Sample List'});

Jag skapade ett nytt TaskSchema objekt med grundläggande information som en uppgift kan ha. Ett virtuellt Mongoose-attribut ställs in för att bekvämt kombinera uppgiftens namn och prioritet. Jag har bara angett en getter här men virtuella sättare stöds också.

Jag definierade också en enkel uppgiftsmetod som heter isHighPriority för att visa hur metoder fungerar med den här inställningen.

I ListSchema definition kommer du att märka hur tasks nyckeln är konfigurerad för att hålla en array av TaskSchema föremål. task nyckel kommer att bli en instans av DocumentArray som tillhandahåller speciella metoder för att hantera inbäddade Mongo-dokument.

För närvarande klarade jag bara ListSchema objekt till mongoose.model och lämnade TaskSchema ut. Tekniskt sett är det inte nödvändigt att vända TaskSchema till en formell modell eftersom vi inte kommer att spara den i sin egen samling. Senare ska jag visa dig hur det inte skadar någonting om du gör det och det kan hjälpa dig att organisera alla dina modeller på samma sätt, särskilt när de börjar sträcka sig över flera filer.

Med List modellinställning låt oss lägga till ett par uppgifter till den och spara dem i Mongo.

var List = mongoose.model('List');
var sampleList = new List({name:'Sample List'});
 
sampleList.tasks.push(
    {name:'task one', priority:1}, 
    {name:'task two', priority:5}
);
 
sampleList.save(function(err) {
    if (err) {
        console.log('error adding new list');
        console.log(err);
    } else {
        console.log('new list successfully saved'); 
    }
});

Attributet tasks på instansen av vår List modell (sampleList ) fungerar som en vanlig JavaScript-array och vi kan lägga till nya uppgifter till den med push. Det viktiga att lägga märke till är tasks läggs till som vanliga JavaScript-objekt. Det är en subtil skillnad som kanske inte är direkt intuitiv.

Du kan verifiera från Mongo-skalet att den nya listan och uppgifterna har sparats i mongo.

db.lists.find()
{ "tasks" : [
    {
        "_id" : ObjectId("4dd1cbeed77909f507000002"),
        "priority" : 1,
        "name" : "task one"
    },
    {
        "_id" : ObjectId("4dd1cbeed77909f507000003"),
        "priority" : 5,
        "name" : "task two"
    }
], "_id" : ObjectId("4dd1cbeed77909f507000001"), "name" : "Sample List" }

Nu kan vi använda ObjectId för att dra upp Sample List och upprepa sina uppgifter.

List.findById('4dd1cbeed77909f507000001', function(err, list) {
    console.log(list.name + ' retrieved');
    list.tasks.forEach(function(task, index, array) {
        console.log(task.name);
        console.log(task.nameandpriority);
        console.log(task.isHighPriority());
    });
});

Om du kör den sista biten av koden får du ett felmeddelande som säger att det inbäddade dokumentet inte har en metod isHighPriority . I den nuvarande versionen av Mongoose kan du inte komma åt metoder på inbäddade scheman direkt. Det finns en öppen biljett för att fixa det och efter att ha ställt frågan till Mongoose Google Group, publicerade manimal45 en användbar lösning som kan användas för tillfället.

List.findById('4dd1cbeed77909f507000001', function(err, list) {
    console.log(list.name + ' retrieved');
    list.tasks.forEach(function(task, index, array) {
        console.log(task.name);
        console.log(task.nameandpriority);
        console.log(task._schema.methods.isHighPriority.apply(task));
    });
});

Om du kör den koden bör du se följande utdata på kommandoraden.

Sample List retrieved
task one
task one (1)
true
task two
task two (5)
false

Med den lösningen i åtanke låt oss vända TaskSchema till en Mongoose-modell.

mongoose.model('Task', TaskSchema);
 
var Task = mongoose.model('Task');
 
var ListSchema = new Schema({
    name: String,
    tasks: [Task.schema]
});
 
mongoose.model('List', ListSchema);
 
var List = mongoose.model('List');

TaskSchema definitionen är densamma som tidigare så jag utelämnade den. När det väl förvandlats till en modell kan vi fortfarande komma åt det underliggande Schema-objektet med hjälp av punktnotation.

Låt oss skapa en ny lista och bädda in två uppgiftsmodellinstanser i den.

var demoList = new List({name:'Demo List'});
 
var taskThree = new Task({name:'task three', priority:10});
var taskFour = new Task({name:'task four', priority:11});
 
demoList.tasks.push(taskThree.toObject(), taskFour.toObject());
 
demoList.save(function(err) {
    if (err) {
        console.log('error adding new list');
        console.log(err);
    } else {
        console.log('new list successfully saved'); 
    }
});

När vi bäddar in uppgiftsmodellinstanserna i listan anropar vi toObject på dem för att konvertera deras data till vanliga JavaScript-objekt som List.tasks DocumentArray väntar. När du sparar modellinstanser på detta sätt kommer dina inbäddade dokument att innehålla ObjectIds .

Det fullständiga kodexemplet är tillgängligt som en sammanfattning. Förhoppningsvis hjälper dessa lösningar till att jämna ut saker och ting när Mongoose fortsätter att utvecklas. Jag är fortfarande ganska ny på Mongoose och MongoDB, så dela gärna med mig av bättre lösningar och tips i kommentarerna. Glad datamodellering!



  1. Kan jag göra två kolumner unika för varandra? eller använda sammansatta primärnycklar i redis?

  2. MongoDB "kan inte hitta index för $geoNear-frågan"

  3. MongoDB räkna distinkt värde?

  4. Infoga element i kapslade arrayer i MongoDB