<p>luwak 4.0.1: middleware pra "perbarui" objek ini tidak mengembalikan objek model</p>

Dibuat pada 30 Mar 2015  ·  40Komentar  ·  Sumber: Automattic/mongoose

Hai, saya punya masalah dengan versi terbaru dari Mongoose. Saya membuat API dengan Express dan Mongoose 4.0.1, dan saya tidak yakin apakah saya melakukan sesuatu yang salah, tetapi kenyataannya adalah setiap kali saya mencoba menggunakan middleware pembaruan pre yang baru dengan cara yang sama Saya menggunakan pre save middleware, objek this tidak mengembalikan objek yang sedang diperbarui, melainkan mengembalikan objek Query .

Contoh dari apa yang saya coba jelaskan:

ExerciseSchema.pre('save', function (next, done) {
        var self = this;
        console.log('exercise:', self); // returns exercise object
        // some validations here
       next();
});
ExerciseSchema.pre('update', function (next, done) {
        var self = this;
        console.log('exercise:', self); // returns Query object instead of exercise object
        // some validations here
       next();
});

Inilah yang saya dapatkan di objek referensi this di dalam middleware, dan saya tidak tahu bagaimana itu berguna bagi saya.

{ _mongooseOptions: {},
  mongooseCollection: 
   { collection: { s: [Object] },
     opts: { bufferCommands: true, capped: false },
     name: 'exercises',
     conn: 
     ... },
   ...
}

Melihat kode sumber, beberapa propertinya didefinisikan di dalam fungsi Query yang didefinisikan dalam ./node_modules/mongoose/lib/query.js :

Apakah ini sesuatu yang tidak terduga atau saya melakukan sesuatu yang salah? Akan menarik untuk memiliki solusi karena saya tidak suka gagasan memvalidasi dalam middleware pada penyimpanan objek dan dipaksa untuk menjalankan validasi langsung pada pengontrol saat memperbarui.

Hal yang sama terjadi dengan middleware findOneAndUpdate pre , tetapi saya tidak mengharapkannya untuk mengembalikan latihan sebelum menemukannya. Faktanya dan menurut pendapat jujur ​​saya, saya pikir akan menarik bahwa findAndUpdate dan findOneAndUpdate pra middlewares memicu find(One) dan memperbarui middlewares, dalam urutan ini, alih-alih memiliki middleware sendiri.

Terima kasih sebelumnya atas bantuan Anda.

won't fix

Komentar yang paling membantu

Ah ok saya melihat Anda menggunakan findOneAndUpdate() daripada update() . Ini adalah dua fungsi yang berbeda dengan kait yang berbeda, jadi jika Anda ingin menambahkan operasi pembaruan ke findOneAndUpdate di pra kait, Anda harus melakukannya

schema.pre('findOneAndUpdate', function() {
  this.findOneAndUpdate({}, { $set: { key: 'value' } });
});

Semua 40 komentar

Secara desain - dokumen yang diperbarui bahkan mungkin tidak ada di memori server. Untuk melakukan itu, luwak harus melakukan findOne() untuk memuat dokumen sebelum melakukan pembaruan(), yang tidak dapat diterima.

Desainnya memungkinkan Anda untuk memanipulasi objek kueri dengan menambahkan atau menghapus filter, memperbarui params, opsi, dll. Misalnya, secara otomatis memanggil .populate() dengan find() dan findOne() , menyetel multi: true opsi secara default pada model tertentu, kontrol akses, dan kemungkinan lainnya .

findOneAndUpdate() sedikit keliru, ia menggunakan perintah mongodb findAndModify yang mendasarinya, tidak sama dengan findOne() + update() . Sebagai operasi terpisah, ia harus memiliki middleware sendiri.

Bagaimana Anda menyarankan memperbarui bidang dokumen selama middleware pembaruan 'pra'?

this.update({ field: val }); akan menambahkan { $set: { field: val } } ke operasi pembaruan sebelum itu terjadi.

Terima kasih telah menjawab, pada versi mana itu seharusnya berfungsi? karena saya menggunakan 4.0.2 dan tidak. Apakah saya harus memanggil "exec" pada kueri?

jika saya menjalankan this.update bukankah saya akan memanggil metode ini http://mongoosejs.com/docs/api.html#query_Query -update?

Saya akhirnya melakukan this.findOneAndUpdate({matcher: "myvalue"}); berharap itu pendekatan yang tepat.

Hmm 4.0.2 harus bekerja. Seperti apa tampilan kode Anda?

Saya baru saja melakukan sesuatu seperti ini:

var schema = mongoose.Schema({
    name: String,
    description: String,
    matcher: String,

});

var generateMatcherUpdate= function(next) {
     var matcher = "generate matcher function"
        this.update({matcher: matcher});

    next();
};

 schema.pre('update', generateMatcherUpdate);

Ah ok saya melihat Anda menggunakan findOneAndUpdate() daripada update() . Ini adalah dua fungsi yang berbeda dengan kait yang berbeda, jadi jika Anda ingin menambahkan operasi pembaruan ke findOneAndUpdate di pra kait, Anda harus melakukannya

schema.pre('findOneAndUpdate', function() {
  this.findOneAndUpdate({}, { $set: { key: 'value' } });
});

dokumentasi man luwak sangat buruk. Bisakah seseorang tolong letakkan ini di sana?

@askdesigners meletakkan apa sebenarnya di sana?

Maaf saya menulis itu di saat stres :)

Hanya kerapuhan kompatibilitas versi yang sebenarnya. Ini bukan masalah yang jelas, dan membuat banyak orang menggaruk-garuk kepala.

Jangan khawatir. Masalah kompatibilitas versi seperti apa yang Anda alami?

Dan bagaimana jika saya ingin membersihkan nilai pada pre.update...Sepertinya saya tidak dapat menemukan cara untuk melakukannya.
Terima kasih!

schema.pre('update', function() {
  var v = this.getUpdate().valueToSanitize;
  this.update({}, { $set: { valueToSanitize: sanitize(v) } });
});

Bagus, saya akan mencobanya!
Terima kasih!!

Hai @vkarpov15 , saya menemukan sesuatu yang menurut saya adalah perilaku yang tidak terduga, atau setidaknya harus didokumentasikan.

Jika saya melakukan sesuatu seperti

MyModel.findOneAndUpdate({a: 1}, {v: '__3'}, function (err, model) {
    console.log(model);
});

Dan pada model saya, saya menerapkan saran Anda

mySchema.pre('findOneAndUpdate', function() {
  var v = this.getUpdate().v;
  this.findOneAndUpdate({}, { $set: { v: sanitize(v) } });
});

Log akan menampilkan '__3' karena kueri pembaruan asli akan dieksekusi setelah pengait. Saya dapat mengubah properti skema lain tetapi semua bidang yang diperbarui pada kueri asli akan tetap sama meskipun diubah di pra-kait.

@CMatias ini adalah kasus di mana Anda harus berhati-hati menggunakan $set atau tidak secara konsisten. Luwak tidak selalu tahu apakah akan membungkus $set , jadi dalam kasus Anda, Anda harus melakukan this.findOneAndUpdate({}, { v: sanitize(v) });

@vkarpov15 terima kasih, itu berhasil. Bisakah Anda menjelaskan secara singkat apa perbedaan antara menggunakan $set dan tidak menggunakannya? Tidak dapat menemukan banyak informasi tentangnya.

Jadi jika Anda menggunakan driver mongodb asli secara langsung dan melakukan coll.findOneAndUpdate({ a: 1 }, { __v: 3 }) , mongodb akan mengambil dokumen pertama dengan a = 1 dan menggantinya dengan dokumen { __v: 3 } modulo _id . Dengan kata lain, itu akan menimpa dokumen yang ada. Untuk mengatur kunci '__v', Anda perlu melakukan coll.findOneAndUpdate({ a: 1 }, { $set: { __v: 3 } }) .

Perilaku ini selalu kontroversial dan rawan kesalahan, jadi secara default luwak mencegah Anda menimpa dokumen. Dengan kata lain, MyModel.findOneAndUpdate({ a: 1 }, { __v: 3 }) menjadi MyModel.collection.findOneAndUpdate({ a: 1 }, { $set: { __v: 3 } }) _kecuali_ Anda menyetel opsi overwrite: true . Namun, Anda dapat melakukan hal-hal aneh seperti MyModel.update({}, { $set: { b: 2 } }).findOneAndUpdate({ a: 1 }, { __v: 3 }, { overwrite: true }) yang membuatnya cukup membingungkan seperti apa status getUpdate() saat ini, jadi kami membiarkan status update apa adanya untuk perangkat tengah.

Saya mencoba memahami semua ini tetapi saya kesulitan menentukan apakah saya dapat memodifikasi dokumen yang akan dikembalikan dari pencarian menggunakan metode middleware ini. Secara khusus, saya ingin "menghias" respons dengan menambahkan bidang tambahan.

Misalnya, jika saya memiliki Skema:

const Thing = new mongoose.Schema({
  name: {type: String}
});

Thing.post('find', function(doc, next){
  doc.newfield = "example text";
  next();
}

Apakah ini mungkin?

Alasan newfield tidak didefinisikan dalam skema adalah karena bergantung pada nilai Thing , nama bidang yang berbeda diperlukan.

Terima kasih!

saya memerlukan plugin khusus untuk menggunakan schema.pre('update')?

Tidak @jrogatis

@vkarpov15

Melihat contoh yang Anda berikan di atas ...:

schema.pre('update', function() {
  var v = this.getUpdate().valueToSanitize;
  this.update({}, { $set: { valueToSanitize: sanitize(v) } });
});

Ini tidak bekerja untuk saya. this.getUpdate().value tidak berisi properti saya value seperti yang disarankan oleh contoh. Sebaliknya itu tersedia di bawah this.getUpdate().$set.property .

Apakah memang seharusnya seperti itu? Apakah saya memahami sesuatu yang salah? Apakah APInya berubah? Apakah ada dokumentasi tentang ini?

@qqilihq dapatkah Anda membuka masalah terpisah dengan skrip repro?

@qqilihq nvm, baru saja melihat bahwa Anda melakukannya: P

@varunjayaraman Sebenarnya masalah terpisah yang saya buka adalah yang berbeda :) Tapi saya akan dengan senang hati membuka yang baru untuk komentar di atas, setelah saya punya waktu luang untuk mengkompilasi contoh.

@qqilihq ah ok, terima kasih!

Persis sama untuk saya seperti yang disebutkan oleh @qqilihq

image

Jadi perilaku yang diinginkan dapat dicapai dengan kode ini:

userSchema.pre('update', function (next) {
  const newEmail = this.getUpdate().$set.email
  if (newEmail) {
    this.update({}, {$set: {email: normalizeEmail(newEmail)}})
  }
  next()
})

Tapi sepertinya saya mencoba menggunakan beberapa bidang yang tidak dimaksudkan untuk ini.

pre metode tidak boleh bekerja dengan this.update , karena "pra"-save dan belum ada yang diperbarui, sementara this.newProp = "value" bekerja dengan sempurna, terima kasih kawan.

Kasus saya adalah:

UserSchema.pre('save', function(next) {
    this.created = Date.now()
    next()
})

Saya memahami alasan di balik memiliki kueri sebagai "ini" di kait pembaruan "pra" tetapi mengapa kait pembaruan "pos" berperilaku dengan cara yang sama? Bukankah seharusnya posting pembaruan memiliki model aktual sebagai "ini"?

Jadi post find akan dieksekusi beberapa kali atau memiliki this sebagai array dari ada beberapa hasil? Dan bagaimana jika tidak ada hasil, apakah post find tidak boleh dijalankan?

Ini semua sangat aneh. IMHO Pra kait semua harus berperilaku sama, dengan this yang merupakan objek yang sedang dimodifikasi dan metode yang bagus seperti isModified untuk memeriksa sesuatu.

Sebenarnya saya pikir saya mengerti sekarang. Saya seharusnya menggunakan metode pra 'simpan' dan kemudian metode this.isNew. Terima kasih!

@ajbraus agak aneh, tapi alternatifnya adalah overhead kinerja yang sangat besar. Misalkan Anda memiliki pembaruanBanyak yang memperbarui jutaan dokumen - luwak harus memuat semuanya ke dalam memori.

Bagaimana seharusnya memeriksa bidang dokumen sebelum pembaruan? Katakanlah saya perlu memeriksa apakah bidang tertentu diisi untuk menetapkan dokumen sebagai "valid", bagaimana saya bisa mengakses seluruh dokumen, dan bukan hanya bidang yang diperbarui? this mengacu pada kueri di sini

@ PDS42 Anda harus menjalankan kueri terpisah untuk memuat dokumen dari mongodb

Apakah ada tautan tertentu dalam dokumentasi luwak di mana semua ini dijelaskan secara lebih mendalam? Saya ingin membacanya dan memahami ini lebih lengkap :).

EDIT:

kait pra pembaruan: https://github.com/Automattic/mongoose/issues/2812
middleware: https://mongoosejs.com/docs/middleware.html
objek kueri: https://mongoosejs.com/docs/api.html#Query
pertanyaan: https://mongoosejs.com/docs/queries.html

Saya mengalami kesulitan menemukan dokumentasi tentang bagaimana tepatnya seseorang harus menggunakan kueri yang dirujuk oleh 'ini' di middleware pembaruan. Misalnya, apa yang terjadi ketika:
this.update({field: "value"}, {$set: {updatedAt: new Date()}}); Apakah ini menambahkan {field: "value"} ke filter? Atau tidak berpengaruh? Apakah ada dokumentasi yang tidak saya lihat?

@ronakvora ada fungsi Query#getConditions() .

schema.pre('update', function() {
  console.log(this.getConditions()); // Will include `{ field: 'value' }`
});

Gotcha, itu akan membantu saya bermain dengan berbagai hal :). Terima kasih!

Ps ini Ronak dari atas. Rupanya saya memiliki dua akun yang masuk di perangkat yang berbeda.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat