[解決済み] なぜMongooseにはスキーマとモデルの両方があるのですか?
質問
この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 の初心者なので、もっといい解決策やヒントをコメントで教えてください。データモデリングに幸あれ!
関連
-
[解決済み】SocketException: アドレスはすでに使用中です。
-
[解決済み] MongoDB の重複レコードを検索する
-
[解決済み] Mongorestore はファイル "db/collection.bson" をどうしたらいいかわからないため、スキップします。
-
[解決済み] Mongo Restart Error -- /var/run/mongodb/mongod.pid が存在する
-
[解決済み] mongodb Failed: error connecting to db server: no reachable servers
-
[解決済み] pandasを使った "大量データ "ワークフロー【終了しました
-
[解決済み】mongooseスキーマにcreated_atとupdated_atフィールドを追加する
-
[解決済み】MongoDBとMongooseの違いについて
-
[解決済み】mongooseの_idと文字列の比較
-
[解決済み] mongoがどのポートをリッスンしているか、mongoシェルから見るにはどうしたらいいですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】SocketException: アドレスはすでに使用中です。
-
[解決済み】MongoDBシェルですべてのコレクションを一覧表示するには?
-
[解決済み] 条件付きでMongoDBを更新する
-
[解決済み] mongodb サービスが開始されない
-
[解決済み] mongodb aggregation sort
-
[解決済み] 複数のキーで "distinct "を効率的に実行するには?
-
[解決済み】MongoDBでデータのバージョニングを実装する方法
-
[解決済み] 日付に基づいたクエリを返す
-
[解決済み] Mongo: 特定のフィールドを持たない項目を検索する
-
[解決済み] Typescript流のMongoose...?