Mongoose neden hem şemalara hem de modellere sahip?


94

İki tür nesne birbirine o kadar yakın görünür ki, her ikisine de sahip olmak gereksizdir. Hem şemalara hem de modellere sahip olmanın amacı nedir ?

Yanıtlar:


61

Genellikle bu tür soruları yanıtlamanın en kolay yolu bir örnek vermektir. Bu durumda, birisi zaten benim için yaptı :)

Buraya bir göz atın:

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

DÜZENLEME: Orijinal gönderi (yorumlarda belirtildiği gibi) artık mevcut değil, bu yüzden onu aşağıda yeniden oluşturuyorum. Geri dönerse veya yeni taşınırsa lütfen bana bildirin.

Firavun faresindeki modellerde şemaları kullanmanın ve bunu neden yapmak isteyeceğinizin iyi bir tanımını verir ve ayrıca şema tamamen yapı vb. İle ilgili iken model aracılığıyla görevleri nasıl iteceğinizi gösterir.

Orijinal Gönderi:

Bir modelin içine bir şema yerleştirmenin basit bir örneğiyle başlayalım.

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

TaskSchemaBir görevin sahip olabileceği temel bilgileri içeren yeni bir nesne oluşturdum . Bir Mongoose sanal özniteliği , Görevin adını ve önceliğini uygun şekilde birleştirmek için ayarlanır. Burada sadece bir alıcı belirledim ancak sanal ayarlayıcılar da destekleniyor.

isHighPriorityYöntemlerin bu kurulumla nasıl çalıştığını göstermek için adında basit bir görev yöntemi de tanımladım .

Gelen ListSchematanım size görevler anahtar bir dizi tutmak için nasıl yapılandırıldığını fark edeceksiniz TaskSchemanesneler. Görev anahtarı, DocumentArraygömülü Mongo belgeleriyle uğraşmak için özel yöntemler sağlayan bir örnek haline gelecektir .

Şimdilik ListSchemanesneyi sadece mongoose.model'e ilettim ve TaskSchema'yı dışarıda bıraktım. Teknik olarak TaskSchemaresmi bir modele dönüştürmeye gerek yok çünkü onu kendi koleksiyonumuza kaydetmeyeceğiz. Daha sonra, yaparsanız hiçbir şeye zarar vermeyeceğini size göstereceğim ve tüm modellerinizi özellikle birden fazla dosyayı yaymaya başladıklarında aynı şekilde düzenlemenize yardımcı olabilir.

İle Listmodeli kurulumu en ona bir çift görevler ekleyebilir ve bunlara tasarruf Mongo için izin verin.

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

ListModelimizin ( simpleList) örneğindeki görevler özniteliği normal bir JavaScript dizisi gibi çalışır ve push kullanarak ona yeni görevler ekleyebiliriz. Dikkat edilmesi gereken önemli şey, görevlerin normal JavaScript nesneleri olarak eklenmesidir. Bu, hemen sezgisel olmayabilecek ince bir ayrımdır.

Mongo kabuğundan yeni listenin ve görevlerin mongo'ya kaydedildiğini doğrulayabilirsiniz.

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" }

Şimdi , görevlerini ObjectIdyukarı çekmek Sample Listve yinelemek için kullanabiliriz .

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

Son kod parçasını çalıştırırsanız, gömülü belgenin bir yöntemi olmadığını söyleyen bir hata alırsınız isHighPriority. Mongoose'un mevcut sürümünde, gömülü şemalardaki yöntemlere doğrudan erişemezsiniz. Bunu düzeltmek için açık bir bilet var ve soruyu Mongoose Google Grubu'na sorduktan sonra, manimal45 şimdilik kullanmak için yararlı bir çözüm yayınladı.

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

Bu kodu çalıştırırsanız, komut satırında aşağıdaki çıktıyı görmelisiniz.

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

Aklımızdaki bu geçici TaskSchemaçözümle , onu bir Mongoose modeline çevirelim.

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');

TaskSchemaTanım Ben bunu sol yüzden önce aynıdır. Bir modele dönüştürüldüğünde, temelde yatan Şema nesnesine nokta gösterimini kullanarak hala erişebiliriz.

Yeni bir liste oluşturalım ve içine iki Görev modeli örneği yerleştirelim.

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

Görev modeli örneklerini Listeye yerleştirirken, toObjectverilerini List.tasks DocumentArraybekledikleri düz JavaScript nesnelerine dönüştürmelerini istiyoruz . Model örneklerini bu şekilde kaydettiğinizde, gömülü belgeleriniz içerecektir ObjectIds.

Kod örneğinin tamamı bir özet olarak mevcuttur . Umarım bu geçici çözümler, Mongoose gelişmeye devam ederken işleri yumuşatmaya yardımcı olur. Mongoose ve MongoDB'de hala oldukça yeniyim, bu yüzden lütfen yorumlarda daha iyi çözümler ve ipuçları paylaşmaktan çekinmeyin. Mutlu veri modelleme!


3
SO'da yayınlanan sorulara yanıt olarak çıplak bağlantıların gönderilmemesi önerilir, çünkü bağlantı çalışmayabilir (bu durumda olduğu gibi). En azından link verdiğiniz makalelerin ilgili bölümlerini kopyalayın / yapıştırın ve alıntı yapın.
Behrang Saeedzadeh

1
bitti - hala Google önbelleğindeydi, çok basit
Adam Comerford

1
Kayıt için, yerleşik belge yöntemi sorunu düzeltildi: github.com/LearnBoost/mongoose/issues/249#ref-commit-e18077a
Dakota

5
Kimsenin geçit törenine yağmur yağdırmaya çalışmıyorum, ancak bu cevap daha çok bir öğretici gibi okuyor: nasıl yanıtlamak, ancak nedenini değil. Daha az oy
almamıza

2
Bu cevabı gördüm (ve oy verdim), bu cevap ondan 2 yıl önce cevaplandı ve kabul edildi. Daha iyi bir cevap bulunacağına sevindim, kimsenin geçit törenine yağmur yağmadı ve Şubat 2015'ten bu yana sorunun yorumlarında atıfta bulunduğunuz cevaba bir bağlantı var, bu yüzden onu kendim bağlama ihtiyacı hissetmedim
Adam Comerford

54

Şema , MongoDB koleksiyonunuzda saklanacak tüm belgelerin yapısını tanımlayan bir nesnedir; tüm veri öğeleriniz için türler ve doğrulayıcılar tanımlamanıza olanak tanır.

Model , adlandırılmış bir koleksiyona kolay erişim sağlayan, koleksiyonu sorgulamanıza ve bu koleksiyona kaydettiğiniz tüm belgeleri doğrulamak için Şemayı kullanmanıza olanak tanıyan bir nesnedir. Şema, Bağlantı ve koleksiyon adı birleştirilerek oluşturulur.

Orijinal olarak Valeri Karpov, MongoDB Blog tarafından ifade edilmiştir.


5

Kabul edilen cevabın aslında sorulan soruyu cevapladığını sanmıyorum. Cevap, Mongoose'un neden bir geliştiricinin hem bir Şema hem de bir Model değişkeni sağlamasını zorunlu kıldığını açıklamıyor . Geliştiriciye olan ihtiyacı ortadan kaldırdıkları bir çerçeve örneğiveri şemasını tanımlamak için django vardır - geliştirici, modellerini models.py dosyasına yazar ve şemayı yönetmek için çerçeveye bırakır. Django ile olan deneyimlerime göre, bunu neden yaptıklarının ilk akla gelen nedeni kullanım kolaylığıdır. Belki daha da önemlisi KURU (kendinizi tekrar etmeyin) prensibidir - modeli değiştirdiğinizde şemayı güncellemeyi hatırlamanıza gerek yoktur - django bunu sizin için yapar! Rails ayrıca sizin için verilerin şemasını da yönetir - bir geliştirici şemayı doğrudan düzenlemez, ancak şemayı işleyen geçişleri tanımlayarak değiştirir.

Mongoose'un şemayı ve modeli ayıracağını anlamamın bir nedeni, iki şemadan bir model oluşturmak isteyeceğiniz örneklerdir. Böyle bir senaryo, yönetmeye değer olandan daha fazla karmaşıklık getirebilir - bir model tarafından yönetilen iki şemanız varsa, bunlar neden tek bir şema değil?

Belki de asıl soru, geleneksel ilişkisel veritabanı sisteminin kalıntısıdır. NoSQL / Mongo dünyasında, belki şema MySQL / PostgreSQL'den biraz daha esnektir ve bu nedenle şemayı değiştirmek daha yaygın bir uygulamadır.


Sanki şema ve model tekrarı yeterli değilmiş gibi , eşleşen bir TypeScript arabirimini korumaya çalışırken daha fazla çoğaltmaya ve hatta bir GraphQL şeması oluştururken daha fazlasına rastlarsınız.
Dan Dascalescu

0

Nedenini anlamak için? Mongoose'un gerçekte ne olduğunu anlamak zorundasın?

Mongoose, MongoDB ve Node JS için bir nesne veri modelleme kitaplığıdır ve daha yüksek düzeyde bir soyutlama sağlar. Yani bu biraz Express ve Node arasındaki ilişkiye benziyor, bu yüzden Express normal Node üzerinde bir soyutlama katmanı iken Mongoose, normal MongoDB sürücüsüne göre bir soyutlama katmanıdır.

Bir nesne veri modelleme kitaplığı, daha sonra bir veritabanıyla etkileşime girecek Javascript kodu yazmamızın bir yoludur. Yani veritabanımıza erişmek için normal bir MongoDB sürücüsü kullanabilirdik, bu gayet iyi çalışırdı.

Ancak bunun yerine Mongoose kullanıyoruz çünkü kutudan çıktığı haliyle bize uygulamalarımızın daha hızlı ve daha basit geliştirilmesine olanak tanıyan çok daha fazla işlevsellik sağlıyor.

Bu nedenle, Mongoose'un bazı özellikleri bize verilerimizi ve ilişkimizi modellemek için şemalar, kolay veri doğrulama, basit bir sorgu API'si, ara katman yazılımı ve çok daha fazlasını sunar.

Mongoose'da bir şema, verilerimizi modellediğimiz, verilerin yapısını, varsayılan değerleri ve doğrulamayı tanımladığımız, ardından bu şemayı alıp ondan bir model oluşturduğumuz, bir model temelde şema etrafında bir sarmalayıcıdır. bu, belgeleri oluşturmak, silmek, güncellemek ve okumak için veritabanıyla fiilen arayüz oluşturmamızı sağlar.

görüntü açıklamasını buraya girin

Şemadan bir model oluşturalım.

const tourSchema = new mongoose.Schema({
  name: {
    type: String,
    required: [true, 'A tour must have a name'],
    unique: true,
  },
  rating: {
    type: Number,
    default: 4.5,
  },
  price: {
    type: Number,
    required: [true, 'A tour must have a price'],
  },
});
//tour model
const Tour = mongoose.model('Tour', tourSchema);

Anlaşmaya göre bir model adının ilk harfi büyük yazılmalıdır.

Firavun faresi ve şema kullanarak oluşturduğumuz modelimizin bir örneğini oluşturalım. ayrıca, veritabanımızla etkileşimde bulunun.

const testTour = new Tour({ // instance of our model
  name: 'The Forest Hiker',
  rating: 4.7,
  price: 497,
});
 // saving testTour document into database
testTour
  .save()
  .then((doc) => {
    console.log(doc);
  })
  .catch((err) => {
    console.log(err);
  });

Yani hem schama hem de modle firavun faresine sahip olmak hayatımızı kolaylaştırıyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.