1. ホーム
  2. mongodb

[解決済み] なぜMongooseにはスキーマとモデルの両方があるのですか?

2023-01-03 03:38:22

質問

この2つのオブジェクトは、互いに近接しているように見えるので、両方を持つことは冗長に感じられます。このような場合に 両方 を持つことに何の意味があるのでしょうか?

どのように解決するのですか?

EDITです。 これは多くの人々にとって有用でしたが、コメントで言及されたように、それは理由よりもむしろquot;方法"に答えています。ありがたいことに、この質問の理由については、他の場所でも回答されています。 この回答は別の質問に対するものです . これは以前からコメントにリンクされていたのですが、読んでもそこまでたどり着けない人も多いかと思いますので、ご了承ください。

この種の質問に答える最も簡単な方法は、しばしば例を挙げることです。 この場合、誰かがすでに私のためにそれをやってくれました :)

こちらを見てください。

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

EDITです。 元の投稿(コメントにあるように)はもう存在しないようなので、以下にそれを再現します。 もし復活していたら、あるいは移動していたら、教えてください。

mongooseのモデル内でスキーマを使うことの適切な説明と、なぜそうしたいのか、また、スキーマが構造などすべてであるのに対して、モデルを通してタスクをプッシュする方法を示してくれています。

オリジナルの投稿です。

まずはモデル内にスキーマを埋め込む簡単な例から。

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

新しく作った TaskSchema オブジェクトを作成し、タスクが持つであろう基本的な情報を持たせました。マングース 仮想属性 は、タスクの名前と優先度を便利に組み合わせるために設定されています。ここではゲッターだけを指定しましたが、仮想セッターもサポートされています。

というシンプルなタスクメソッドも定義しました。 isHighPriority というシンプルなタスクメソッドも定義し、このセットアップでメソッドがどのように動作するかをデモしています。

ListSchema の定義を見てみると、どのように tasks の配列を保持するように構成されていることに注意してください。 TaskSchema オブジェクトの配列を保持します。また task のインスタンスになります。 DocumentArray のインスタンスになり、埋め込まれた Mongo ドキュメントを処理するための特別なメソッドを提供します。

今のところ ListSchema オブジェクトを mongoose.model に変換し TaskSchema を抜いています。技術的には TaskSchema を正式なモデルにする必要はありません。なぜなら、それ自身のコレクションに保存しないからです。後で、そうしても何も害がないこと、特に複数のファイルにまたがるようになったときに、すべてのモデルを同じ方法で整理するのに役立つことをお見せします。

を使うと List モデルをセットアップした状態で、これにいくつかのタスクを追加して、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'); 
    }
});

のインスタンスの tasks 属性は List モデル ( sampleList ) は通常の JavaScript の配列のように動作し、push を使って新しいタスクを追加することができます。注目すべき重要な点は tasks が通常の JavaScript オブジェクトとして追加されていることです。これは微妙な違いであり、すぐには直感的に理解できないかもしれません。

Mongo シェルから、新しいリストとタスクが 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" }

これで ObjectId を引き出して Sample List を取り出し、そのタスクを繰り返し実行します。

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

最後のコードを実行すると、埋め込まれたドキュメントがメソッドを持っていないというエラーが発生します。 isHighPriority . 現在のバージョンの Mongoose では、埋め込みスキーマのメソッドに直接アクセスすることはできません。埋め込みスキーマのメソッドに直接アクセスするには オープンチケット があり、Mongoose Google Group に質問を投げかけたところ、manimal45 が役に立つ回避策を投稿してくれたので、今はそれを使っています。

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

このコードを実行すると、コマンドライン上に以下のような出力が表示されるはずです。

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

この回避策を念頭に置いて TaskSchema をMongooseモデルに変換してみましょう。

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 の定義は以前と同じなので省きました。一旦モデルに変換されると、ドット記法を使ってその基礎となるSchemaオブジェクトにアクセスすることができます。

新しいリストを作成し、その中に2つのタスクモデルインスタンスを埋め込んでみましょう。

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

タスクモデルのインスタンスをリストに埋め込んでいるので、そのインスタンスに対して toObject を呼び出して、データをプレーンな JavaScript オブジェクトに変換しています。 List.tasks DocumentArray が期待するものです。この方法でモデルインスタンスを保存すると、埋め込みドキュメントには ObjectIds .

完全なコード例は gist として利用可能です。 . これらの回避策が、Mongoose が発展していく過程で円滑に事を運ぶのに役立つことを願っています。私はまだ Mongoose と MongoDB の初心者なので、もっといい解決策やヒントをコメントで教えてください。データモデリングに幸あれ!