<p>mongoose 4.0.1: البرامج الوسيطة السابقة على "التحديث" لا يقوم هذا الكائن بإرجاع كائن النموذج</p>

تم إنشاؤها على ٣٠ مارس ٢٠١٥  ·  40تعليقات  ·  مصدر: Automattic/mongoose

مرحبًا ، لدي مشكلة مع أحدث إصدار من 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 المسبق إلى البحث (واحد) وتحديث البرامج الوسيطة ، بهذا الترتيب ، بدلاً من امتلاك برمجيات وسيطة خاصة به.

شكرا مقدما لمساعدتكم.

won't fix

التعليق الأكثر فائدة

حسنًا ، أرى أنك تستخدم findOneAndUpdate() بدلاً من update() . هاتان الوظيفتان المميزتان مع خطافات مميزة ، لذلك إذا كنت ترغب في إضافة عمليات التحديث إلى findOneAndUpdate في خطاف مسبق ، فيجب عليك القيام بذلك

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

ال 40 كومينتر

حسب التصميم - قد لا يكون المستند الجاري تحديثه في ذاكرة الخادم. للقيام بذلك ، يجب أن يقوم النمس بعمل 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

image

لذلك يمكن تحقيق السلوك المطلوب من خلال هذا الكود:

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' }`
});

مسكتك ، سيساعدني ذلك على اللعب بالأشياء :). شكرا!

ملاحظة هذا هو روناك من فوق. يبدو أن لدي حسابين مسجلين الدخول على أجهزة مختلفة.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات