保存後にマングースが生息


96

新しく保存されたオブジェクトの作成者フィールドに手動または自動でデータを入力することはできません...私が見つけることができる唯一の方法は、私がやりたくない既存のオブジェクトを再クエリすることです。

これはセットアップです:

var userSchema = new mongoose.Schema({   
  name: String,
});
var User = db.model('User', userSchema);

var bookSchema = new mongoose.Schema({
  _creator: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
  description: String,
});
var Book = db.model('Book', bookSchema);

これは私が私の髪を引っ張っているところです

var user = new User();
user.save(function(err) {
    var book = new Book({
        _creator: user,
    });
    book.save(function(err){
        console.log(book._creator); // is just an object id
        book._creator = user; // still only attaches the object id due to Mongoose magic
        console.log(book._creator); // Again: is just an object id
        // I really want book._creator to be a user without having to go back to the db ... any suggestions?
    });
});

編集:最新のマングースがこの問題を修正し、追加機能を追加しました。新しい承認済みの回答を参照してください。

回答:


136

:あなたはこれを行うにモデルの移入機能を使用することができるはずhttp://mongoosejs.com/docs/api.html#model_Model.populateの 代わりに、本のために保存ハンドラで:

book._creator = user;

あなたは次のようなことをするでしょう:

Book.populate(book, {path:"_creator"}, function(err, book) { ... });

おそらく回答が遅すぎてあなたを助けることはできませんが、私は最近これに行き詰まり、他の人に役立つかもしれません。


これが仮想属性で機能すればいいのですが。のようなcreator.profile
チョビー14年

ユーザーが仮想属性を持っている場合、それらは含まれません。
曲がりくねった14

保存する直前に参照をnullに設定しようとしたときにいくつかの問題がありましたが、これは私にとってはうまくいきました。保存後、Book.populateを呼び出すと、フィールドに以前の参照値が誤って入力され、その理由を理解できません。DBにNULLが正常に含まれています。
Daniel Flippance 2014年

2
そして、これはデータベースを再クエリしませんか?!
Nepoxx 2015

9
これはデータベースを再クエリしています
ブバカゾウバ2016年

36

誰かがまだこれを探している場合に備えて。

Mongoose 3.6には、多数の優れた機能が導入されています。

book.populate('_creator', function(err) {
 console.log(book._creator);
});

または:

Book.populate(book, '_creator', function(err) {
 console.log(book._creator);
});

詳しくはhttps://github.com/LearnBoost/mongoose/wiki/3.6-Release-Notes#populationをご覧ください。

ただし、この方法では、引き続きユーザーに対してクエリを実行できます。

追加のクエリなしでそれを達成するための小さなトリックは次のようになります:

book = book.toObject();
book._creator = user;

やっbook._creator = user;た後、save()現在のすべての回答の中で唯一の正しい答えは、他のすべての答えは、追加のクエリが必要です。
Mr5o1

23

私のための解決策はexecPopulate、そのように使用することでした

const t = new MyModel(value)
return t.save().then(t => t.populate('my-path').execPopulate())

2
@Francoisに感謝します。私の命を救ってくれました。私はこれの解決策を見つけようとしていました。最終的にそれを得た。
Rupesh

18

promiseを返すソリューション(コールバックなし):

Document#populateを使用

book.populate('creator').execPopulate();

// summary
doc.populate(options);               // not executed
doc.populate(options).execPopulate() // executed, returns promise

可能な実装

var populatedDoc = doc.populate(options).execPopulate();
var populatedDoc.then(doc => {
   ... 
});

ドキュメントの作成については、こちらをご覧ください


いい物。ありがとう
Joel H

11

それが私を助けたので、詳しく説明し、別の例を挙げます。これは、保存後に部分的に入力されたオブジェクトを取得したい場合に役立ちます。方法も少し異なります。それを行うための正しい方法を探して、1〜2時間以上費やしました。

  post.save(function(err) {
    if (err) {
      return res.json(500, {
        error: 'Cannot save the post'
      });
    }
    post.populate('group', 'name').populate({
      path: 'wallUser',
      select: 'name picture'
    }, function(err, doc) {
      res.json(doc);
    });
  });

9

私のような完全な初心者のための事柄を明確にするためにこれに追加したいと思いました。

注意しないと非常に混乱するのは、3つのまったく異なるPopulateメソッドがあることです。これらは異なるオブジェクト(モデルとドキュメント)のメソッドであり、異なる入力を受け取り、異なる出力(ドキュメントとPromise)を提供します。

ここでは、困惑している人のためのものです:

Document.prototype.populate()

完全なドキュメントを参照してください。

これはドキュメントで機能し、ドキュメントを返します。元の例では、次のようになります。

book.save(function(err, book) {
    book.populate('_creator', function(err, book) {
        // Do something
    })
});

これはドキュメントで機能し、ドキュメントを返すため、次のようにそれらをチェーンできます。

book.save(function(err, book) {
    book
    .populate('_creator')
    .populate('/* Some other ObjectID field */', function(err, book) {
        // Do something
    })
});

しかし、私のように愚かであってはいけません。

book.save(function(err, book) {
    book
    .populate('_creator')
    .populate('/* Some other ObjectID field */')
    .then(function(book) {
        // Do something
    })
});

注意:Document.prototype.populate()はドキュメントを返すため、これはナンセンスです。あなたが約束をしたいなら、あなたは必要です...

Document.prototype.execPopulate()

完全なドキュメントを参照してください。

これはドキュメントで機能しますが、ドキュメントに解決されるプロミスを返します。つまり、次のように使用できます。

book.save(function(err, book) {
    book
    .populate('_creator')
    .populate('/* Some other ObjectID field */')
    .execPopulate()
    .then(function(book) {
        // Do something
    })
});

それは良いです。最後に、...

Model.populate()

完全なドキュメントを参照してください。

これはモデル動作し、約束を返します。したがって、使用方法は少し異なります。

book.save(function(err, book) {
    Book // Book not book
    .populate(book, { path: '_creator'})
    .then(function(book) {
        // Do something
    })
});

それが他のいくつかの新人を助けたことを願っています。


1

残念ながら、これはマングースに関する長年の問題であり、まだ解決されていません。

https://github.com/LearnBoost/mongoose/issues/570

あなたができることはこれのためにあなた自身のカスタムゲッター/セッターを書くことです(そして別のプロパティで実際 _customerに設定します)。例えば:

var get_creator = function(val) {
    if (this.hasOwnProperty( "__creator" )) {
        return this.__creator;
    }
    return val;
};
var set_creator = function(val) {
    this.__creator = val;
    return val;
};
var bookSchema = new mongoose.Schema({
  _creator: {
     type: mongoose.Schema.Types.ObjectId,
     ref: 'User',
     get: get_creator,
     set: set_creator
  },
  description: String,
});

注:私はそれをテストしなかったし.populate、純粋なidを設定すると奇妙に動作する可能性があります。


彼らは問題を修正することを望んでいないようです。
ピクラー、

1
この問題は3.6で修正されています
mkoryak 2013年

@Pyklerは、この回答が無効になるため、承認済みの回答を最も高い評価の回答に変更する必要があります
Matt Fletcher

1

マングース5.2.7

これは私のために働きます(ちょうど頭痛の種!)

exports.create = (req, res, next) => {
  const author = req.userData;
  const postInfo = new Post({
    author,
    content: req.body.content,
    isDraft: req.body.isDraft,
    status: req.body.status,
    title: req.body.title
  });
  postInfo.populate('author', '_id email role display_name').execPopulate();
  postInfo.save()
    .then(post => {
      res.status(200).json(post);
    }).catch(error => {
      res.status(500).json(error);
    });
};

0

おそらくsth。お気に入り

Book.createAsync(bookToSave).then((savedBook) => savedBook.populateAsync("creator"));

これを機能させるための最も優れた、最も問題の少ない方法です(Bluebirdの約束を使用)。


0

最終的には、スキーマ、query_adapter、data_adapter関数を宣言し、文字列を事前に入力するカレー可能なPromise関数をいくつか作成しました。より短い/より単純な実装では、より簡単です。

それはおそらく超効率的ではありませんが、実行ビットは非常にエレガントだと思いました。

githubファイル:curry_Promises.js

宣言

const update_or_insert_Item = mDB.update_or_insert({
    schema : model.Item,
    fn_query_adapter : ({ no })=>{return { no }},
    fn_update_adapter : SQL_to_MDB.item,
    populate : "headgroup"
    // fn_err : (e)=>{return e},
    // fn_res : (o)=>{return o}
})

実行

Promise.all( items.map( update_or_insert_Item ) )
.catch( console.error )
.then( console.log )
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.