Firavun faresi, kaydettikten sonra doldurulur


99

Oluşturucu alanını yeni kaydedilmiş bir nesneye manuel veya otomatik olarak dolduramıyorum ... bulabilmemin tek yolu, yapmaktan nefret ettiğim zaten sahip olduğum nesneleri yeniden sorgulamaktır.

Kurulum şu şekildedir:

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

Burası saçımı çektiğim yer

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

DÜZENLEME: en son firavun faresi bu sorunu çözdü ve doldurma işlevi eklendi, yeni kabul edilen yanıta bakın.

Yanıtlar:


140

Bunu yapmak için Model'in doldurma işlevini kullanabilmeniz gerekir: http://mongoosejs.com/docs/api.html#model_Model.populate Kitap için kaydetme işleyicisinde, bunun yerine:

book._creator = user;

şöyle bir şey yaparsın:

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

Muhtemelen size yardımcı olmak için çok geç bir cevap, ama son zamanlarda buna takılı kaldım ve başkaları için faydalı olabilir.


Bunun sanal özniteliklerle çalışması iyi olurdu. beğencreator.profile
chovy

kullanıcının bazı sanal öznitelikleri varsa bunlar dahil edilmez.
chovy

Bu benim için işe yaradı, ancak başvuruyu kaydetmeden hemen önce null olarak ayarlamaya çalıştığımda bazı sorunlar yaşadım. Kaydettikten sonra, Book.populate'i çağırmak, alanı önceki referans değeriyle yanlış bir şekilde doldurdu ve nedenini bulamıyorum. DB, boş değeri başarıyla içeriyor.
Daniel Flippance

2
Ve bu olacak değil yeniden sorgu veritabanı ?!
Nepoxx

9
bu veritabanını yeniden
sorguluyor

37

Birinin hala bunu araması durumunda.

Mongoose 3.6, doldurmak için birçok harika özellik getirdi:

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

veya:

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

daha fazlasını görmek için: https://github.com/LearnBoost/mongoose/wiki/3.6-Release-Notes#population

Ancak bu şekilde yine de kullanıcıyı yeniden sorgulayabilirsiniz.

Ekstra sorgular olmadan bunu başarmak için küçük bir numara şu olabilir:

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

mevcut tüm cevaplar arasında tek doğru cevaptan book._creator = user;sonra yapmak save(), diğer tüm cevaplar ek bir sorgu gerektirir.
Mr5o1

25

Benim için çözüm execPopulate, böyle kullanmaktı

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

3
Çok teşekkürler @Francois, Hayatımı kurtardın, buna çözüm bulmaya çalışıyordum. FInally anladım.
Rupesh

22

Bir söz döndüren çözüm (geri çağırma yok):

Belge # doldurmayı kullan

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

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

Olası Uygulama

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

Belge doldurma hakkında buradan bilgi edinin .


İyi şeyler. Teşekkürler
Joel H

11

Sadece detaylandırmak ve bana yardımcı olduğu için başka bir örnek vermek için. Bu, kaydettikten sonra kısmen doldurulmuş nesneleri almak isteyenlere yardımcı olabilir. Yöntem de biraz farklı. Doğru yolu bulmak için bir veya iki saatten fazla zaman harcadım.

  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

Kendim gibi tamamen çaylaklar için bazı şeyleri açıklığa kavuşturmak için buna bir şeyler eklemeyi düşündüm.

Dikkatli olmazsanız büyük ölçüde kafa karıştıran şey, üç farklı popülasyon yöntemi olmasıdır. Farklı nesnelerin yöntemleridir (Modele karşı Belge), farklı girdiler alır ve farklı çıktılar verir (Belge ve Söz).

İşte şaşkın olanlar için:

Document.prototype.populate ()

Tam belgelere bakın.

Bu, belgeler üzerinde çalışır ve bir belge döndürür. Orijinal örnekte şöyle görünecektir:

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

Belgeler üzerinde çalıştığı ve bir belge döndürdüğü için, bunları şu şekilde birbirine zincirleyebilirsiniz:

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

Ama benim gibi aptal olma ve bunu yapmaya çalış:

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

Unutmayın: Document.prototype.populate () bir belge döndürür, bu yüzden bu saçmalıktır. Bir söz istiyorsan, ihtiyacın olan ...

Document.prototype.execPopulate ()

Tam belgelere bakın.

Bu, belgeler üzerinde çalışır, ancak belgeye çözüm getiren bir söz verir. Başka bir deyişle, bunu şu şekilde kullanabilirsiniz:

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

Bu daha iyi. Son olarak, var ...

Model.populate ()

Tam belgelere bakın.

Bu , modeller üzerinde çalışır ve bir söz verir. Bu nedenle biraz farklı kullanılır:

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

Umarım bu yeni gelenlere yardımcı olmuştur.


1

Maalesef bu, firavun faresi ile ilgili henüz çözülmediğine inandığım uzun süredir devam eden bir sorun:

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

Ne yapabilirsiniz size kendi özel alıcı / ayarlayıcı (ve set yazmaktır gerçek _customer bunun için ayrı bir özellik olarak). Örneğin:

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

NOT: Test etmedim .populateve saf kimliği ayarlarken garip bir şekilde çalışabilir .


Görünüşe göre sorunu çözmek istemiyorlar.
Pykler

1
bu sorun 3.6
mkoryak

@Pykler, kabul edilen yanıtı daha önce en yüksek puan alan yanıtla değiştirmeniz gerekiyor, çünkü bu yanıt artık geçerli değil
Matt Fletcher

1

Firavun Faresi 5.2.7

Bu benim için çalışıyor (sadece çok fazla baş ağrısı!)

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

Muhtemelen öyledir. sevmek

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

Bu işi yapmanın en güzel ve en az sorunlu yolu olacaktır (Bluebird vaatlerini kullanmak).


0

sonunda şemanızı, sorgu_ bağdaştırıcınızı, data_adapter işlevlerinizi açıkladığınız ve dizeyi önceden doldurduğunuz bazı curry -able Promise işlevlerini yazdı. Daha kısa / daha basit bir uygulama için daha kolay.

Muhtemelen süper verimli değil, ancak yürütme kısmının oldukça zarif olduğunu düşündüm.

github dosyası: curry_Promises.js

beyan

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

icra

Promise.all( items.map( update_or_insert_Item ) )
.catch( console.error )
.then( console.log )
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.