Saya tidak dapat secara manual atau otomatis mengisi kolom pencipta pada objek yang baru disimpan ... satu-satunya cara yang dapat saya temukan adalah dengan menanyakan ulang objek yang sudah saya miliki yang tidak ingin saya lakukan.
Ini adalah pengaturannya:
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);
Di sinilah saya menarik rambut saya
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?
});
});
EDIT: luwak terbaru memperbaiki masalah ini dan menambahkan fungsi populasi, lihat jawaban baru yang diterima.
creator.profile
Jika ada yang masih mencari ini.
Mongoose 3.6 telah memperkenalkan banyak fitur keren untuk diisi:
book.populate('_creator', function(err) { console.log(book._creator); });
atau:
Book.populate(book, '_creator', function(err) { console.log(book._creator); });
lihat lebih lanjut di: https://github.com/LearnBoost/mongoose/wiki/3.6-Release-Notes#population
Namun dengan cara ini Anda masih akan menanyakan pengguna itu lagi.
Trik kecil untuk menyelesaikannya tanpa pertanyaan tambahan adalah:
sumber
book._creator = user;
setelahsave()
adalah satu-satunya jawaban yang benar di antara semua jawaban saat ini, semua jawaban lainnya memerlukan pertanyaan tambahan.Solusi bagi saya adalah menggunakan
execPopulate
, seperti ituconst t = new MyModel(value) return t.save().then(t => t.populate('my-path').execPopulate())
sumber
Solusi yang mengembalikan sebuah janji (tanpa panggilan balik):
Gunakan Document # populate
book.populate('creator').execPopulate(); // summary doc.populate(options); // not executed doc.populate(options).execPopulate() // executed, returns promise
Implementasi yang Mungkin
var populatedDoc = doc.populate(options).execPopulate(); var populatedDoc.then(doc => { ... });
Baca tentang populasi dokumen di sini .
sumber
Hanya untuk menguraikan dan memberikan contoh lain, karena itu membantu saya. Ini mungkin membantu mereka yang ingin mengambil objek yang terisi sebagian setelah menyimpan. Metodenya juga sedikit berbeda. Menghabiskan lebih dari satu atau dua jam mencari cara yang benar untuk melakukannya.
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); }); });
sumber
Saya pikir saya akan menambahkan ini untuk mengklarifikasi hal-hal untuk noob lengkap seperti saya.
Yang sangat membingungkan jika Anda tidak berhati-hati adalah ada tiga metode populasi yang sangat berbeda. Mereka adalah metode dari objek yang berbeda (Model vs. Dokumen), mengambil input yang berbeda dan memberikan output yang berbeda (Dokumen vs. Janji).
Ini dia untuk mereka yang bingung:
Document.prototype.populate ()
Lihat dokumen lengkapnya.
Yang ini bekerja pada dokumen dan mengembalikan dokumen. Dalam contoh aslinya, akan terlihat seperti ini:
book.save(function(err, book) { book.populate('_creator', function(err, book) { // Do something }) });
Karena berfungsi pada dokumen dan mengembalikan dokumen, Anda dapat menyatukannya seperti ini:
book.save(function(err, book) { book .populate('_creator') .populate('/* Some other ObjectID field */', function(err, book) { // Do something }) });
Tapi jangan konyol, seperti saya, dan coba lakukan ini:
book.save(function(err, book) { book .populate('_creator') .populate('/* Some other ObjectID field */') .then(function(book) { // Do something }) });
Ingat: Document.prototype.populate () mengembalikan dokumen, jadi ini tidak masuk akal. Jika Anda menginginkan janji, Anda perlu ...
Document.prototype.execPopulate ()
Lihat dokumen lengkapnya.
Yang ini berfungsi pada dokumen NAMUN mengembalikan janji yang menyelesaikan dokumen. Dengan kata lain, Anda bisa menggunakannya seperti ini:
book.save(function(err, book) { book .populate('_creator') .populate('/* Some other ObjectID field */') .execPopulate() .then(function(book) { // Do something }) });
Itu lebih baik. Akhirnya, ada ...
Model.populate ()
Lihat dokumen lengkapnya.
Yang ini bekerja pada model dan mengembalikan janji. Oleh karena itu digunakan sedikit berbeda:
book.save(function(err, book) { Book // Book not book .populate(book, { path: '_creator'}) .then(function(book) { // Do something }) });
Harapan itu membantu beberapa pendatang baru lainnya.
sumber
Sayangnya ini adalah masalah lama dengan luwak yang saya yakin belum terselesaikan:
https://github.com/LearnBoost/mongoose/issues/570
Apa yang dapat Anda lakukan adalah menulis getter / setter kustom Anda sendiri (dan menyetel real
_customer
di properti terpisah) untuk ini. Sebagai contoh: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, });
CATATAN: Saya tidak mengujinya dan mungkin bekerja dengan aneh
.populate
dan saat menyetel id murni.sumber
Luwak 5.2.7
Ini bekerja untuk saya (hanya banyak sakit kepala!)
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); }); };
sumber
Mungkin sth. Suka
Book.createAsync(bookToSave).then((savedBook) => savedBook.populateAsync("creator"));
Akan menjadi cara terbaik dan paling tidak bermasalah untuk membuat ini bekerja (Menggunakan janji Bluebird).
sumber
akhirnya menulis beberapa fungsi Promise yang bisa digunakan untuk mendeklarasikan skema, query_adapter, fungsi data_adapter, dan mengisi string terlebih dahulu. Untuk implementasi yang lebih singkat / sederhana lebih mudah.
Ini mungkin tidak super efisien, tapi saya pikir sedikit eksekusi cukup elegan.
file github: curry_Promises.js
deklarasi
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} })
eksekusi
Promise.all( items.map( update_or_insert_Item ) ) .catch( console.error ) .then( console.log )
sumber