مرحبًا ، لدي مشكلة مع أحدث إصدار من Mongoose. أنا أقوم بإنشاء واجهة برمجة تطبيقات باستخدام Express و Mongoose 4.0.1 ، ولست متأكدًا مما إذا كنت أفعل شيئًا خاطئًا ، ولكن الحقيقة هي أنني كلما حاولت استخدام البرنامج الوسيط الجديد pre
بنفس الطريقة استخدم pre
save middleware ، this
لا يعيد الكائن الكائن الجاري تحديثه ، وبدلاً من ذلك يقوم بإرجاع الكائن Query
.
مثال على ما أحاول شرحه:
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();
});
هذا ما أحصل عليه في الكائن المرجعي this
داخل البرنامج الوسيط ، ولا أعرف كيف يكون مفيدًا بالنسبة لي.
{ _mongooseOptions: {},
mongooseCollection:
{ collection: { s: [Object] },
opts: { bufferCommands: true, capped: false },
name: 'exercises',
conn:
... },
...
}
بالنظر إلى الكود المصدري ، يتم تحديد بعض خصائصه داخل الدالة Query
المحددة في ./node_modules/mongoose/lib/query.js
:
هل هذا شيء غير متوقع أو أفعل شيئًا خاطئًا؟ سيكون من المثير للاهتمام أن يكون لديك حل لأنني لا أحب فكرة التحقق من صحة حفظ الكائن داخل البرنامج الوسيط وإجباري على تشغيل عمليات التحقق مباشرة على وحدة التحكم عند التحديث.
يحدث نفس الشيء مع البرامج الوسيطة findOneAndUpdate pre
، لكنني لا أتوقع أن تعيد التمرين قبل العثور عليه. في الواقع ، وفي رأيي الصادق ، أعتقد أنه سيكون من المثير للاهتمام أن يؤدي البحث عن البرامج الوسيطة وتحديثها وإيجاد OneAndUpdate المسبق إلى البحث (واحد) وتحديث البرامج الوسيطة ، بهذا الترتيب ، بدلاً من امتلاك برمجيات وسيطة خاصة به.
شكرا مقدما لمساعدتكم.
حسب التصميم - قد لا يكون المستند الجاري تحديثه في ذاكرة الخادم. للقيام بذلك ، يجب أن يقوم النمس بعمل findOne () لتحميل المستند قبل إجراء التحديث () ، وهو أمر غير مقبول.
يهدف التصميم إلى تمكينك من معالجة كائن الاستعلام عن طريق إضافة أو إزالة عوامل التصفية وتحديث المعلمات والخيارات وما إلى ذلك. على سبيل المثال ، استدعاء .populate () تلقائيًا مع find () و findOne () ، مع تعيين multi: true
الخيار افتراضيًا في نماذج معينة ، والتحكم في الوصول ، وإمكانيات أخرى .
findOneAndUpdate()
هو تسمية خاطئة قليلاً ، فهو يستخدم الأمر mongodb findAndModify
الأساسي ، وهو ليس مثل findOne()
+ update()
. كعملية منفصلة ، يجب أن يكون لها برمجيات وسيطة خاصة بها.
كيف تقترح تحديث حقل مستند أثناء البرامج الوسيطة "السابقة" بعد ذلك؟
سيضيف $ this.update({ field: val });
{ $set: { field: val } }
لعملية التحديث قبل حدوثها.
شكرا على الرد ، على أي إصدار من المفترض أن يعمل؟ لأنني أستخدم 4.0.2 وهو لا يفعل ذلك. هل يجب علي استدعاء "exec" في الاستعلام؟
إذا قمت بتشغيل this.update ، فلن أستدعي هذه الطريقة http://mongoosejs.com/docs/api.html#query_Query -update؟
انتهى بي الأمر بفعل this.findOneAndUpdate ({matcher: "myvalue"})؛ نأمل أن يكون هذا هو النهج الصحيح.
يجب أن يعمل Hmm 4.0.2. كيف تبدو التعليمات البرمجية الخاصة بك؟
لقد فعلت شيئًا كهذا:
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);
حسنًا ، أرى أنك تستخدم findOneAndUpdate()
بدلاً من update()
. هاتان الوظيفتان المميزتان مع خطافات مميزة ، لذلك إذا كنت ترغب في إضافة عمليات التحديث إلى findOneAndUpdate
في خطاف مسبق ، فيجب عليك القيام بذلك
schema.pre('findOneAndUpdate', function() {
this.findOneAndUpdate({}, { $set: { key: 'value' } });
});
وثائق رجل النمس سيئة للغاية. هل يمكن لأحد أن يضع هذا هناك؟
askdesigners وضع بالضبط ما هناك؟
آسف لقد كتبت ذلك في لحظة من التوتر :)
فقط ضعف توافق الإصدار حقًا. إنها ليست مشكلة واضحة وتترك الكثير من الناس في حيرة من أمرهم.
لا قلق. ما نوع مشكلات توافق الإصدار التي تواجهها؟
وماذا لو كنت أرغب في تعقيم قيمة عند التحديث المسبق ... يبدو أنني لا أستطيع إيجاد طريقة للقيام بذلك.
شكرا!
schema.pre('update', function() {
var v = this.getUpdate().valueToSanitize;
this.update({}, { $set: { valueToSanitize: sanitize(v) } });
});
جميل ، سأحاول ذلك!
شكرا!!
مرحبًا @ vkarpov15 ، لقد صادفت شيئًا أود قوله هو نوع من السلوك غير المتوقع ، أو على الأقل يجب توثيقه.
إذا فعلت شيئًا مثل
MyModel.findOneAndUpdate({a: 1}, {v: '__3'}, function (err, model) {
console.log(model);
});
وعلى نموذجي أنفذ اقتراحك
mySchema.pre('findOneAndUpdate', function() {
var v = this.getUpdate().v;
this.findOneAndUpdate({}, { $set: { v: sanitize(v) } });
});
سينتج السجل "__3" حيث سيتم تنفيذ استعلام التحديث الأصلي بعد موضع الخطاف. أنا قادر على تغيير خصائص المخطط الأخرى ولكن جميع الحقول التي تم تحديثها في الاستعلام الأصلي ستبقى كما هي حتى إذا تم تغييرها في موضع الإضافة.
CMatias هذه هي الحالة التي تحتاج فيها إلى توخي الحذر بشأن استخدام $set
أو عدم استخدامه باستمرار. لا يعرف النمس بالضرورة ما إذا كان يجب أن يلتف في $set
، لذلك في حالتك يجب أن تفعل this.findOneAndUpdate({}, { v: sanitize(v) });
@ vkarpov15 شكرا ، التي عملت. هل يمكن أن تشرح باختصار الفرق بين استخدام $set
وعدم استخدامه؟ لا يمكن العثور على الكثير من المعلومات حول هذا الموضوع.
لذلك إذا كنت تستخدم برنامج التشغيل الأصلي mongodb مباشرة وقمت بعمل coll.findOneAndUpdate({ a: 1 }, { __v: 3 })
، فسيأخذ mongodb المستند الأول بـ a = 1 ويستبدله بالمستند { __v: 3 }
modulo _id
. بمعنى آخر ، سيتم استبدال المستند الحالي. لتعيين المفتاح "__v" فقط ، عليك القيام بـ coll.findOneAndUpdate({ a: 1 }, { $set: { __v: 3 } })
.
لطالما كان هذا السلوك مثيرًا للجدل وعرضة للخطأ ، لذا يمنعك النمس افتراضيًا من الكتابة فوق المستند. بمعنى آخر ، يصبح $ MyModel.findOneAndUpdate({ a: 1 }, { __v: 3 })
MyModel.collection.findOneAndUpdate({ a: 1 }, { $set: { __v: 3 } })
_ إلا إذا قمت بتعيين الخيار overwrite: true
. ومع ذلك ، يمكنك القيام بأشياء غريبة مثل MyModel.update({}, { $set: { b: 2 } }).findOneAndUpdate({ a: 1 }, { __v: 3 }, { overwrite: true })
مما يجعل الأمر محيرًا للغاية بالنسبة للوضع الحالي getUpdate()
، لذلك نترك الحالة update
كما هي للوسيطة.
أحاول أن أفهم كل هذا ولكني أجد صعوبة في تحديد ما إذا كان بإمكاني تعديل المستند الذي سيتم إرجاعه من اكتشاف باستخدام طرق البرامج الوسيطة هذه. على وجه التحديد ، أود "تزيين" الرد عن طريق إضافة حقول إضافية.
على سبيل المثال ، إذا كان لدي مخطط:
const Thing = new mongoose.Schema({
name: {type: String}
});
Thing.post('find', function(doc, next){
doc.newfield = "example text";
next();
}
هل هذا ممكن؟
سبب عدم تحديد newfield
في المخطط هو أنه بناءً على قيم Thing
، هناك حاجة إلى أسماء حقول مختلفة.
شكرا!
أحتاج إلى أي مكون إضافي محدد لاستخدام schema.pre ("تحديث")؟
لا jrogatis
هههههههههههههه
بالنظر إلى المثال الذي ذكرته أعلاه ...:
schema.pre('update', function() {
var v = this.getUpdate().valueToSanitize;
this.update({}, { $set: { valueToSanitize: sanitize(v) } });
});
هذا لا يعمل بالنسبة لي. لا يحتوي this.getUpdate().value
على الممتلكات الخاصة بي value
كما يوحي المثال. بدلاً من ذلك ، يتوفر بسعر أقل من this.getUpdate().$set.property
.
هل من المفترض ان يكون هكذا؟ هل أفهم شيئا خاطئا؟ هل تغيرت API؟ هل هناك أي توثيق حول هذا؟
qqilihq هل يمكنك فتح مشكلة منفصلة باستخدام برنامج نصي repro؟
qqilihq nvm ، فقط رأيت أنك فعلت: P.
varunjayaraman في الواقع ، القضية المنفصلة التي فتحتها هي قضية مختلفة :) لكنني سأفتح واحدة جديدة للتعليق أعلاه ، بمجرد أن يكون لدي بعض الدقائق الإضافية لتجميع مثال.
qqilihq آه حسنًا ، شكرًا!
بالضبط نفس الشيء بالنسبة لي كما ذكر من قبل qqilihq
لذلك يمكن تحقيق السلوك المطلوب من خلال هذا الكود:
userSchema.pre('update', function (next) {
const newEmail = this.getUpdate().$set.email
if (newEmail) {
this.update({}, {$set: {email: normalizeEmail(newEmail)}})
}
next()
})
لكن يبدو أنني أحاول استخدام بعض الحقول غير المخصصة لهذا الغرض.
لا يجب أن تعمل الطريقة pre
مع this.update
، لأنها "حفظ مسبق" ولا يوجد شيء لتحديثه بعد ، بينما this.newProp = "value"
يعمل بشكل مثالي ، شكرًا يا رفاق.
حالتي هي:
UserSchema.pre('save', function(next) {
this.created = Date.now()
next()
})
أتفهم السبب وراء وجود الاستعلام كـ "this" في رابط التحديث "السابق" ولكن لماذا يتصرف رابط التحديث "post" بطريقة مماثلة؟ ألا يجب أن يكون النموذج الفعلي بعد التحديث "هذا"؟
إذن ، سيتم تنفيذ البحث عن المشاركات عدة مرات أو يكون لديه this
كمصفوفة من النتائج المتعددة؟ وماذا لو لم تكن هناك نتائج ، هل يجب ألا يتم تشغيل البحث عن المشاركة؟
هذا كله غريب جدا. IMHO يجب أن تتصرف جميع الخطافات المسبقة بنفس الطريقة ، مع this
وهو الكائن الذي يتم تعديله وطرق لطيفة مثل isModified للتحقق من الأشياء.
في الواقع أعتقد أنني فهمت الآن. يجب أن أستخدم طريقة "الحفظ" المسبقة ثم طريقة this.isNew الجديدة. شكرا!
ajbraus هذا غريب بعض الشيء ، لكن البديل هو الأداء الهائل. لنفترض أن لديك تحديثًا للعديد من المستندات التي تقوم بتحديث الملايين من المستندات - سيتعين على النمس تحميلها جميعًا في الذاكرة.
كيف يفترض أن يتحقق المرء من حقول المستند قبل التحديثات؟ لنفترض أنني بحاجة إلى التحقق مما إذا كانت حقول معينة مملوءة لتعيين المستند على أنه "صالح" ، كيف يمكنني الوصول إلى المستند بأكمله ، وليس فقط الحقول التي يتم تحديثها؟ يشير this
إلى الاستعلام هنا
@ PDS42 ، سيتعين عليك تشغيل استعلام منفصل لتحميل المستند من mongodb
هل هناك ارتباط معين في وثائق النمس حيث يتم شرح كل هذا بمزيد من العمق؟ أحب أن أقرأها وأفهمها بشكل كامل :).
تعديل:
خطافات التحديث المسبق: https://github.com/Automattic/mongoose/issues/2812
البرامج الوسيطة: https://mongoosejs.com/docs/middleware.html
كائن الاستعلام: https://mongoosejs.com/docs/api.html#Query
الاستفسارات: https://mongoosejs.com/docs/queries.html
أواجه مشكلة في العثور على وثائق حول كيفية استخدام المرء للاستعلامات المشار إليها بواسطة "هذا" في البرنامج الوسيط للتحديث. على سبيل المثال ، ماذا يحدث عندما:
this.update({field: "value"}, {$set: {updatedAt: new Date()}});
هل يضيف هذا {field: "value"}
إلى الفلتر؟ أم أنه ليس له تأثير؟ هل هناك وثائق لا أراها؟
ronakvora هناك دالة Query#getConditions()
.
schema.pre('update', function() {
console.log(this.getConditions()); // Will include `{ field: 'value' }`
});
مسكتك ، سيساعدني ذلك على اللعب بالأشياء :). شكرا!
ملاحظة هذا هو روناك من فوق. يبدو أن لدي حسابين مسجلين الدخول على أجهزة مختلفة.
التعليق الأكثر فائدة
حسنًا ، أرى أنك تستخدم
findOneAndUpdate()
بدلاً منupdate()
. هاتان الوظيفتان المميزتان مع خطافات مميزة ، لذلك إذا كنت ترغب في إضافة عمليات التحديث إلىfindOneAndUpdate
في خطاف مسبق ، فيجب عليك القيام بذلك