Mongoose: pre、postミドルりェアはfindByIdAndUpdateで実行されたせん

䜜成日 2012幎06月15日  Â·  102コメント  Â·  ゜ヌス: Automattic/mongoose

次のコヌドを削枛するためにfindAndUpdateメ゜ッドが提瀺されおいるためです。

 Model.findById(_id, function (err, doc) {
      if (doc) {
          doc.field = 'value';
          doc.save(function (err) {
                 // do something;
          });
      }
 });

これに

   .findByIdAndUpdate(_id, {$set: {field: 'value'}}, function (err, doc) {
        // do something 
    });

プレミドルりェアずポストミドルりェアをたったく同じように䜿甚する必芁がありたす。 珟時点では、findByIdAndUpdateを䜜成しおも、ポストミドルりェアは実行されたせん。

最も参考になるコメント

こんにちは、

問題が解決したこずは知っおいたすが、答えに完党に満足しおいるわけではありたせん。 findOneAndUpdateおよび他の同様の操䜜のために、少なくずも保存埌たたは曎新埌のミドルりェアがあるべきではありたせんか ドキュメントが返されるので倧䞈倫のようです。 プレミドルりェアやModel.updateには適しおいたせん、私は同意したす。

これにより、サポヌトできるはずの䞀郚の操䜜を珟圚認識しおいないmongoosasticなどのプラグむンの機胜が倧幅に向䞊したす。

ミドルりェアがない堎合、プラグむンで曎新埌の操䜜を管理する方法に぀いお誰かが考えおいたすか

ありがずう

党おのコメント102件

意図的に。 フックを呌び出すためのドキュメントがありたす。

蚂正、フックを呌び出すためのドキュメントはありたせん。

そう pre、postミドルりェアを呌び出したい堎合は、最初のアプロヌチを䜿甚する必芁がありたすか

はい、それは正しいです。 Model.update、findByIdAndUpdate、findOneAndUpdate、findOneAndRemove、findByIdAndRemoveは、デヌタベヌスで盎接実行されるすべおのコマンドです。

これはガむドで明確に説明する必芁がありたす。特に、同じペヌゞで怜蚌に぀いお話しおいお、 findByIdAndUpdateを「より良い」ず説明しおいる堎合はそうです。

「より良い」リンクをクリックするず、の完党なドキュメントに移動したす。
怜蚌などを説明する方法。

プルリク゚ストを送信しお、より良いず思うものを远加しおください。 これは
そうするのはずおも簡単です
https://github.com/LearnBoost/mongoose/blob/master/CONTRIBUTING.md

2012幎10月31日氎曜日午埌6時3分、Jesse [email protected]曞き蟌み

これは、ガむドhttp://mongoosejs.com/docs/documents.htmlで明確に説明する必芁がありたす。
特に、同じペヌゞで怜蚌に぀いお話しおいる堎合は、
findByIdAndUpdateを「より良い」ず衚珟する

—
このメヌルに盎接返信するか、Gi tHubhttps//github.com/LearnBoost/mongoose/issues/964#issuecomment-9967865で衚瀺しおください。

アヌロン
@aaronheckmann https://twitter.com/#!/aaronheckmann

ミドルりェアドキュメントにメモを远加

プルリク゚スト https //github.com/LearnBoost/mongoose/pull/1750

こんにちは、

問題が解決したこずは知っおいたすが、答えに完党に満足しおいるわけではありたせん。 findOneAndUpdateおよび他の同様の操䜜のために、少なくずも保存埌たたは曎新埌のミドルりェアがあるべきではありたせんか ドキュメントが返されるので倧䞈倫のようです。 プレミドルりェアやModel.updateには適しおいたせん、私は同意したす。

これにより、サポヌトできるはずの䞀郚の操䜜を珟圚認識しおいないmongoosasticなどのプラグむンの機胜が倧幅に向䞊したす。

ミドルりェアがない堎合、プラグむンで曎新埌の操䜜を管理する方法に぀いお誰かが考えおいたすか

ありがずう

@albanm特定のメ゜ッドはマングヌスを完党にバむパスするため、ミドルりェアフックを取埗したせん。 AFAIK、フックを実行させる唯䞀の方法は、䞊蚘のように別々のfind()ずsave()の呌び出しを䜿甚するこずです。

私はそれを理解し、それは理にかなっおいたす。 特定のメ゜ッドの前にフェッチがないため、プレミドルりェアは問題倖です。 しかし、それでも、mongooseは、曎新されたドキュメントを返し、いく぀かのポストフックをトリガヌする曎新操䜜をラップできる必芁がありたす。

@albanmは正しいず思いたす。同じ関数を䜿甚するず、同じ関数が必芁になる堎合がありたす。 これらの「盎接曎新」メ゜ッドを、フックが存圚するかどうかを確認するためのむンタヌセプトでラップするのはどうですか フックが存圚する堎合はそれを䜿甚するか、そうでない堎合は元の曎新メ゜ッドを呌び出したす。

+1

+1

+1

+1

+1

+1

-1
機胜芁求を受け取りたすが、ミドルりェアを䜿甚する時間が長くなるず、デヌタベヌス曎新スクリプトや通垞の操䜜では日垞的ではないその他の項目を呌び出すずきに、ミドルりェアを頻繁にバむパスする必芁がありたす。 静的メ゜ッドを䜿甚するこずにより、䞊蚘の機胜芁求をすでに実装しおいるカスタムラッパヌを非垞に簡単に䜜成できたす。 マングヌスは珟圚バヌゞョン4のアむデアを受け入れおいるため、この芏暡のAPIの倉曎がv3で発生する可胜性はほずんどありたせん。 これをv4ディスカッションに移しおください。

ただし、保存呌び出しでミドルりェアを無効にできた堎合は、+ 1になりたす。 別の関数から枡されたマングヌスオブゞェクトを芋぀けお、単に.saveを実行したいこずがよくありたす。この状況では、新しいク゚リを䜜成するよりも.saveを実行する方が望たしいです。 これが可胜であれば、それを指摘しおください

いずれにせよ、玠晎らしいラむブラリ。 玠晎らしいメンテナぞの称賛。 それなしで私がどのように動䜜するかわかりたせん。

+1

これらのメ゜ッドのフックを远加する簡単な方法は、埋め蟌み関数を䞊曞きするこずです。

_update = UserModel.update
UserModel.update = (conditions, update) ->
  update.updatedAt or= new Date
  _update.apply this, arguments

その埌、mongooseを呌び出すたびに、デヌタのupdatedAtキヌが修正されたす。

このモデルのリンボを詊しおみおください。 これはマングヌスモデルの単玔なラッパヌであり、すべおのスキヌマぞの静的/メ゜ッド/䞊曞きのバむンドをサポヌトし、rpcメ゜ッドを呌び出しおmongodbをク゚リしたす。

+1、この機胜が必芁です...

私はその理由をある皋床理解しおいたすが、アトミック曎新のフックがないため、実際にはMongooseはやや無意味になっおいたす。 アトミック曎新を䜿甚するず、怜蚌やデフォルトなどが実行されないため、ODMを䜿甚する目的党䜓が無効になりたす。 怜玢/保存を䜿甚するず機胜したすが、これが垞に䜿甚されるずいう保蚌はありたすか

さらに、通垞、䞍可分操䜜ではないため、怜玢/保存は避けようずしたす。 MongoDBは、匷力なアトミックク゚リおよび曎新機胜を提䟛するこずにより、トランザクションサポヌトの欠劂を補いたす。 したがっお、これらのアトミック操䜜を䜿甚したすが、ミドルりェアのサポヌトがない堎合、MongooseはネむティブのMongoClientよりも倚くの䟡倀を提䟛したせん。

http://aaronheckmann.tumblr.com/post/48943525537/mongoose-v3-part-1-versioningの䟋でさえ、 updateを䜿甚するため、ミドルりェアをバむパスしたす。 バヌゞョン管理たたはミドルりェアを適切に䜿甚できたすが、䞡方を組み合わせるこずはできたせんか 本圓に、それを持っおいるこずのポむントはどこにありたすか

私は技術的な理由さえ完党には理解しおいたせん update coの堎合。 デヌタベヌス操䜜をラップアラりンドしたす。実際に曎新を行う前に怜蚌/カスタマむズを実行できるように、呌び出しをむンタヌセプトしおク゚リオブゞェクトを枡すこずができないのはなぜですか。

@joerx +1で十分です.. :)しかし、あなたの掚論は完璧です。

3.9.xブランチは、 findずfindOneのプリフックずポストフックをサポヌトしおいたす。 findOneAndUpdateずupdateのサポヌトを簡単に远加できるはずです。

この機胜は統合されおいたすか

したがっお、 pre('findOneAndUpdate') $フックずpost('findOneAndUpdate')フックはマスタヌにあり、曎新フックはただありたせん。 これらのいずれかを含むリリヌスはただありたせん。

では、.updateの埌に事前保存がトリガヌされるのでしょうか

いいえ。 Query.update()甚に別のupdate()フックがありたす。 保存フックはク゚リフックずは異なりたす。

@ vkarpov15アップデヌトフックのサポヌトドキュメントにリンクしおいただけたすか pre('findOneAndUpdate')ずpost('findOneAndUpdate')がい぀リリヌスされるかに぀いお䜕か蚀いたいこずはありたすか

@karlstanton use 4.0.0-rc2、 npm install mongoose@unstable :)

'use strict';

var Promise  = require('bluebird');
var mongoose = Promise.promisifyAll(require('mongoose'));

var counterSchema = new mongoose.Schema({
    total: {
        type:    Number,
        default: 0
    }
});

counterSchema.post('findOneAndUpdate', function (doc) {
    console.log(doc.total);
});

var Counter = mongoose.model('Counter', counterSchema);

Promise.coroutine(function *() {
    yield mongoose.connectAsync(process.env.MONGODB_URI);
    console.log('Connected');
    let counter = yield Counter.createAsync({});
    console.log(`${counter.total}`);
    for (let i = 0; i < 10; i++) {
        yield Counter.findOneAndUpdateAsync({ _id: counter.id }, { $inc: { total: 1} });
    }
})();
0
0
1
2
3
4
5
6
7
8
9

䞀歩遅れおいるようです。 私は䜕が欠けおいたすか

AH、 newフラグのデフォルトの重倧な倉曎。 基瀎ずなるドラむバヌずの䞀貫性に぀いおは䜕か蚀いたいこずがありたすが、特にこの新しいフックを怜蚎する堎合、それは本圓に盎感に反しおいるず蚀わざるを埗たせん。

@neverfox :)

ええ@neverfox良いキャッチ。 この倉曎はリリヌスノヌトに蚘茉されおおり、2262で倉曎された理由に぀いお詳しく説明しおいたす。

その理由は、mongodbノヌドドラむバヌ、mongodbシェル、実際のmongodbサヌバヌなどでnewがデフォルトでfalseであり、ラッパヌレむダヌが非暙準のデフォルトを蚭定するず、開発者の生掻が困難になるためです。 これをひどく間違っおいるモゞュヌルの私の暙準的な䟋は、 gulp-uglifyです。これは、uglify-jsのデフォルトの束をオヌバヌラむドしたす。

問題は解決されおいるようですが、バヌゞョン4.0.2の機胜はただ䞍安定なバヌゞョンのたたですか Scema.pre 'update'を䜿甚したfindOneAndUpdateたたは4.0.2バヌゞョンを䜿甚したSchema.pre 'findOneAndUpdate'では実行されないようです。 関数に枡さなければならないものがありたせんか

プレフック@CaptainStaplerzをどのように宣蚀しおいたすか

findOneAndUpdateミドルりェアフックは4.0.2で利甚できたすか これを䜿甚するために3.8から最新のマングヌス4.0.2にアップグレヌドしたしたが、middlware Document.schema.post 'findOneAndUpdate'、関数docがsaveやremoveのようにトリガヌされたせん

@honitusはあなたのコヌドを芋せおくれたす

@ vkarpov15-迅速な察応に感謝したす。

blog.controller、js

// Updates an existing Blog in the DB, adds comment
exports.update = function(req, res) {

Blog.findOneAndUpdate(
     {"_id": req.body._id,},
      {"$push": {"comments": buildComment}},
     {safe: true, upsert: true}, function (err, workspace) {
      if (err) {
         return handleError(res, err);
       }
       return res.send(200);
      }
   );

}

blog.socket.js

/**
 * Broadcast updates to client when the model changes
 */

'use strict';

var Blog= require('./blog.model');

exports.register = function(socket) {
//SAVE WORKS
  Blog.schema.post('save', function (doc) {
    onSave(socket, doc);
  });

// IS NOT TRIGGERED :(
 Blog.schema.post('findOneAndUpdate', function (doc) {
    onComment(socket, doc);
  });

  Blog.schema.post('remove', function (doc) {
    onRemove(socket, doc);
  });
}

//SAVE WORKS when a new blog is created
function onSave(socket, doc, cb) {
  socket.emit('blog:save', doc);
}

// IS NOT TRIGGERED :(
function onComment(socket, doc, cb) {
  socket.emit('blog:findOneAndUpdate', doc);
}

function onRemove(socket, doc, cb) {
  socket.emit('blog:remove', doc);
}

@ vkarpov15再開しおいただきありがずうございたす。 これは、findOneAndUpdateのフックが4.0.2になく、4.0.3に含めるこずを蚈画しおいるこずを意味したすか

@ vkarpov15フックを宣蚀するコヌドは次のずおりです。

...
var TodoSchema = new mongoose.Schema({
  name: {type: String, required: true},
  note: String,
  completed: {type: Boolean, default: false},
  updatedAt: {type: Date, default: Date.now},
  user: {
    type: mongoose.Schema.ObjectId,
    ref: 'Users'
  }
});
...
// Not executed
TodoSchema.pre('update', function() {
  console.log('------------->>>>>> update updatedAt')
  this.updatedAt = Date.now();
});
// Not executed
TodoSchema.pre('findOneAndUpdate', function() {
  console.log('------------->>>>>> update updatedAt')
  this.updatedAt = Date.now();
});

そしお、これが私がアップデヌトず呌ぶずころです

...
router.route('/:id')
.put(function(req, res, next) {
  TodoModel.findOneAndUpdate({_id: req.params.id, user: req.user.id}, req.body, {new: true}, function(err, post) {
    if(err) return next(err);
    if(post) {
      res.status(200).json(post);
    }
    else {
      next(newSystemError(errorCodes.TODO_NOT_FOUND, undefined, req.params.id));
    }
  });
});

私の知る限り、 findOneAndUpdate()フックはそこにあるはずですが、機胜しおいない堎合はバグです

@CaptainStaplerz詊しおみおください

TodoSchema.pre('update', function(next) {
  console.log('------------->>>>>> update updatedAt')
  this.updatedAt = Date.now();
  next();
});

たた、 console.logステヌトメントが実行されおいるのでしょうか、それずも、予期しない結果をもたらすのはDate.nowの郚分だけでしょうか。

@ vkarpov15
゜ヌスコヌドを倉曎し、実装の远加 964https//github.com/Automattic/mongoose/commit/e98ef98e857965c4b2ae3339fdd7eefd2a5a9913で行った倉曎を远加したした

今では魅力のように機胜したす。 だから私は修正がメむンにチェックむンされおいないず思いたす

@honitusマングヌス4.0.2を䜿甚しおいたすか その倉曎は、実際には4.0.0以降にコミットされおいたす。

honitus $ npmマングヌスバヌゞョンを衚瀺
4.0.2

@honitusが間違っお行っおいるのは、モデルのコンパむル埌にスキヌマにフックを远加しおいるずいうこずです。 Model.schema.pre('remove');は機胜しないず予想されたす。モデルドキュメントの「最初のモデルのコンパむル」を参照しおください。 最初にフックをスキヌマにアタッチするず、動䜜するはずです。これが、コヌドずテストの違いです。

@CaptainStaplerzコヌドを再珟するために私が芋぀けるこずができる唯䞀の方法は、空の曎新を䜿甚するこずです。 以䞋のコヌドは機胜したす

var mongoose = require('mongoose');
mongoose.set('debug', true);
var util = require('util');

mongoose.connect('mongodb://localhost:27017/gh964');

var TodoSchema = new mongoose.Schema({
  name: {type: String, required: true},
  note: String,
  completed: {type: Boolean, default: false},
  updatedAt: {type: Date, default: Date.now},
  user: {
    type: mongoose.Schema.ObjectId,
    ref: 'Users'
  }
});
TodoSchema.pre('update', function() {
  console.log('------------->>>>>> update updatedAt')
  this.updatedAt = Date.now();
});
TodoSchema.pre('findOneAndUpdate', function() {
  console.log('------------->>>>>> update updatedAt')
  this.updatedAt = Date.now();
});

var Todo = mongoose.model('Todo', TodoSchema);

Todo.update({}, { note: "1" }, function(err) {
  if (err) {
    console.log(err);
  }
  console.log('Done');
  process.exit(0);
});

ただし、曎新を空にするず、次のようになりたす。

var mongoose = require('mongoose');
mongoose.set('debug', true);
var util = require('util');

mongoose.connect('mongodb://localhost:27017/gh964');

var TodoSchema = new mongoose.Schema({
  name: {type: String, required: true},
  note: String,
  completed: {type: Boolean, default: false},
  updatedAt: {type: Date, default: Date.now},
  user: {
    type: mongoose.Schema.ObjectId,
    ref: 'Users'
  }
});
TodoSchema.pre('update', function() {
  console.log('------------->>>>>> update updatedAt')
  this.updatedAt = Date.now();
});
TodoSchema.pre('findOneAndUpdate', function() {
  console.log('------------->>>>>> update updatedAt')
  this.updatedAt = Date.now();
});

var Todo = mongoose.model('Todo', TodoSchema);

Todo.update({}, { }, function(err) {
  if (err) {
    console.log(err);
  }
  console.log('Done');
  process.exit(0);
});

曎新前フックは実行されなくなりたした。 これはあなたが芋おいるものず䞀臎しおいたすか

@ vkarpov15
Model.schema.pre 'remove'; 角床フルスタックによっお自動的に䜜成されるスタブの1぀です
実装964e98ef98を远加したした
䞋に1行远加するだけです
this._schema.s_.hooks.wrap 'findOneAndUpdate'、Query.base.findOneAndUpdate、
4.0.2の1526行目を参照しおください-this.model.hooks.wrap 'findOneAndUpdate'、Query.base.findOneAndUpdate、

1526行目を-this.schema.s.hooks.wrap 'findOneAndUpdate'、Query.base.findOneAndUpdate、
そしおそれは動䜜したす。

これは仕様によるものです。 Mongooseは、モデルのコンパむル埌にスキヌマフックを倉曎するこずを蚱可しないこずになっおいたす぀たり、 mongoose.model()呌び出し。そのため、これは機胜しなくなりたす。

@ vkarpov15私は今、次のようにフックを機胜させるこずができたした。それは愚かなタむプミスか䜕か他のものだったに違いありたせん。

TodoSchema.pre('findOneAndUpdate', function(next) {
  console.log('------------->>>>>> update updatedAt: ', this.updatedAt);
  this.updatedAt = Date.now();
  next();
});

ただし、「this」は曎新されたモデルを参照しおいないようですただし、「save」フックでは参照しおいたすか。したがっお、this.updatedAtはundefinedを参照したす。

'findOneAndUpdate'フックの 'updatedAt'フィヌルドを曎新するにはどうすればよいですか

これを明確にするドキュメントをさらに远加する必芁がありたす- findOneAndUpdateを呌び出すず、曎新䞭のドキュメントがメモリに存圚しない可胜性があるため、 thisオブゞェクトは、ク゚リミドルりェアのドキュメントではなくク゚リを参照したす。 this.update({ $set: { updatedAt: Date.now() } });お詊しください

@ vkarpov15 this.update({ $set: { updatedAt: Date.now() } });を機胜させるこずができたせんでしたが、 findOneAndUpdateフックのドキュメントをthis._update['$setOnInsert'].updatedAt=Date.now();で正垞に曎新できたした。

そのような内郚状態の調敎に䟝存しないこずを匷くお勧めしたす。 this.update()を機胜させるこずができなかったこずに、私はかなり驚いおいたす。フックがどのように芋えるかを芋せおいただけたすか

もちろん 4.0.2を䜿甚しおいるこずに泚意しおください

tagSchema.pre('findOneAndUpdate',function(next){
  var self = this;

  //NOTE THAT 'this' in the findOneAndUpdate hook refers to the query, not the document
  //https://github.com/Automattic/mongoose/issues/964

  geoData.country.findOne({'_id':self._update['$setOnInsert'].countryCode}).select('_id name cca2 cca3 ccn3').lean().exec(function(err,country){
    if (err){throw err;}
    if (!country){throw 'no coutnry';}
    self._update['$setOnInsert'].country=country;
    next();
  });
});

アプリの他の堎所でドキュメントを初期化するずきに明らかにこれを凊理できたすが、すべおがMongooseに含たれおいるず䟿利です。 どんな考えでも歓迎したす

ええ、私は混乱しおいお、あなたがupdateを䜿っおいるず思いたした。 以䞋のスクリプト

var mongoose = require('mongoose');
mongoose.set('debug', true);
var util = require('util');

mongoose.connect('mongodb://localhost:27017/gh964');

var TodoSchema = new mongoose.Schema({
  name: {type: String, required: true},
  note: String,
  completed: {type: Boolean, default: false},
  updatedAt: {type: Date, default: Date.now},
  user: {
    type: mongoose.Schema.ObjectId,
    ref: 'Users'
  }
});
TodoSchema.pre('findOneAndUpdate', function() {
  this.findOneAndUpdate({}, { updatedAt: Date.now() });
});

var Todo = mongoose.model('Todo', TodoSchema);

Todo.findOneAndUpdate({}, { note: "1" }, function(err) {
  if (err) {
    console.log(err);
  }
  console.log('Done');
  process.exit(0);
});

正しく機胜し、目的のク゚リを実行したす。

Mongoose: todos.findAndModify({}) [] { '$set': { note: '1', updatedAt: new Date("Thu, 07 May 2015 20:36:39 GMT") } } { new: false, upsert: false }
Done

だから䜿っおください

TodoSchema.pre('findOneAndUpdate', function() {
  this.findOneAndUpdate({}, { updatedAt: Date.now() });
});

mqueryの内郚状態を手動で操䜜する代わりに、実際に䜕をしおいるのかを本圓に理解しおいない限り、これは通垞は悪い考えです。

これは機胜しおいたすか 私のために働くフックだけが「保存」であり、残りは完党に無芖されたす。 私は4.0.6で実行しおいたす。 ありがずう

@agjsはコヌド䟋を提䟛しおください。

UserController.prototype.updateAvatar = function (req, res) {
    return new Promise(function (resolve, reject) {
        CompanyDetails.update({
            _author: req.user._id
        }, {
            avatarPath: req.files.file
        }, function (error, updated) {
            if (error) {
                reject(error);
            } else {
                resolve(updated);
            }
        });
    }).then(function (resolved) {
        res.sendStatus(204).send(updated);
    }).catch(function (error) {
        next(error);
    })

};

CompanyAvatarSchema.pre('update', function (next) {
    console.log('pre save');
    let VirtualModel = this,
        parent = this.ownerDocument(),
        PATH = path.normalize('./public/images/uploads/avatars/' + parent._id);

    mkdirp(PATH, function (error) {
        if (error) {
            next(error);
        } else {
            fs.rename(VirtualModel.path, path.join(PATH, VirtualModel.name), function (error2) {
                if (error2) {
                    next(error2);
                } else {
                    next();
                }
            });
        }
    });

});

model.createずpre-saveを䜿甚しお、別のモデルに別のプリフックがあり、正垞に機胜したす。

曎新を行うず、フックが衚瀺されず、console.logも衚瀺されたせん。 findOneAndUpdateも詊したしたが、実際には機胜したせん...面癜いこずに、このスレッド党䜓を調べたした。い぀ものように、公匏ドキュメントを確認したしたが、そこでも機胜するず䞻匵しおいたす。

䞊蚘のコヌドのCompanyAvatarSchemaずCompanyDetailsの関係は䜕ですか

䌚瀟の詳现には、サブドキュメントずしおCompanyAvatar.schemaがありたす

avatarPath: {
        type: [CompanyAvatar.schema],
        required: true
    }

たた、事前フックだけでなく、怜蚌も完党に無芖されたす。 このサブドキュメントは入力されたすが、怜蚌ずプレフックの䞡方を無芖したす。 私はすべおをグヌグルで怜玢し、これも詊したしたが、動䜜する継ぎ目はありたせん。 テストのためにク゚リを倉曎しお、新しい別名var parent = new Parentでモデルを䜜成しお呌び出すず、機胜したす。

CompanyDetails.update()を呌び出しおいたすが、preフックは別のスキヌマで定矩されおいたす。 ク゚リミドルりェアは、ネストされたスキヌマのpre('update') atmを起動したせん。

たた、「怜蚌が完党に無芖される」堎合のより完党なコヌド䟋も提䟛しおください。

これは、プロファむルを曎新しおいるナヌザヌの怜蚌ず事前フックのために䜜成された私の䌚瀟のアバタヌスキヌマですアバタヌの写真

'use strict';

let mongoose = require('mongoose'),
    mkdirp = require('mkdirp'),
    fs = require('fs'),
    path = require('path'),
    Schema = mongoose.Schema;

let CompanyAvatarSchema = new Schema({
    name: String,
    width: Number,
    height: Number,
    size: Number,
    type: String
});


CompanyAvatarSchema.path('type').validate(function (type) {
    return /^image\//.test(type);
}, 'Image type not allowed!');

CompanyAvatarSchema.path('size').validate(function (size) {
    return size < 5;
}, 'Image too big!');



CompanyAvatarSchema.virtual('path').set(function (path) {
    return this._path = path;
}).get(function () {
    return this._path;
});


CompanyAvatarSchema.virtual('public_path').get(function () {
    var parent = this.ownerDocument();
    var PATH = path.normalize('images/uploads/avatars/' + parent._id);
    if (this.name) {
        return path.join(PATH, this.name);
    }
});

CompanyAvatarSchema.set('toJSON', {
    getters: true
});

CompanyAvatarSchema.pre('findOneAndUpdate', function (next) {
    console.log('pre save');
    let VirtualModel = this,
        parent = this.ownerDocument(),
        PATH = path.normalize('./public/images/uploads/avatars/' + parent._id);

    mkdirp(PATH, function (error) {
        if (error) {
            next(error);
        } else {
            fs.rename(VirtualModel.path, path.join(PATH, VirtualModel.name), function (error2) {
                if (error2) {
                    next(error2);
                } else {
                    next();
                }
            });
        }
    });

});


let runValidatorsPlugin = function (schema, options) {
    schema.pre('findOneAndUpdate', function (next) {
        this.options.runValidators = true;
        next();
    });
};

CompanyAvatarSchema.plugin(runValidatorsPlugin);

let CompanyAvatar = mongoose.model('CompanyAvatar', CompanyAvatarSchema);
module.exports = CompanyAvatar;

これがcompany_detailsスキヌマで、company_avatarはサブドキュメントです。

let CompanyDetailsSchema = new mongoose.Schema({
    _author: [{
        type: Schema.Types.ObjectId,
        ref: 'CompanyAccount'
    }],
    company_name: {
        type: String,
        es_indexed: true,
        es_boost: 2.0
    },
    contact_email: {
        type: String,
        es_indexed: true
    },
    website: {
        type: String,
        es_indexed: true
    },
    country: {
        type: String,
        es_indexed: true
    },
    industry: {
        type: String,
        es_indexed: true
    },
    address: {
        type: String,
        es_indexed: true
    },
    about: {
        type: String,
        es_indexed: true
    },
    avatarPath: {
        type: [CompanyAvatar.schema],

    }
});

そしお、これがアップデヌトプロファむルコントロヌラヌず、このアップデヌトを実行する前に怜蚌/フックする必芁があるavatarPathです。

UserController.prototype.updateAvatar = function (req, res, next) {
    let updates = {
        $set: {
            avatarPath: req.files.file
        }
    };
    return new Promise(function (resolve, reject) {
        CompanyDetails.findOneAndUpdate({
            _author: req.user._id
        }, updates, function (error) {
            if (error) {
                reject(error);
            } else {
                resolve('done');
            }
        });
    }).then(function () {
        res.sendStatus(204);
    }).catch(function (error) {
        next(error);
    });

};

基本的に、私のmongodbにはreq.files.fileのフィヌルドが入力されたすが、それ以倖の堎合、怜蚌は無芖され、フックは機胜したせん。

問題は、pre 'findOneAndUpdate'ミドルりェアがネストされたスキヌマで定矩されおいるこずです。 珟圚、mongooseはトップレベルスキヌマのク゚リミドルりェアのみを起動するため、 CompanyDetailsSchemaで定矩されたミドルりェアは次のように起動されたす3125

+1

@ vkarpov15わかりたした

TodoSchema.pre('findOneAndUpdate', function() {
  this.findOneAndUpdate({}, { updatedAt: Date.now() });
});

プロパティをハヌド倀に蚭定するように機胜したすが、パスワヌドをハッシュするなど、プロパティをどのように_読み取り、倉曎_したすか

TodoSchema.pre('findOneAndUpdate', function() {
  this.findOneAndUpdate({}, { password: hashPassword(.....?....) });
});

䜕かご意芋は これはかなり䞀般的なナヌスケヌスですよね たたは、人々は通垞、findを芋぀けおから、saveを分離したすか

TodoSchema.pre('findOneAndUpdate', function() {
  this.findOneAndUpdate({}, { password: hashPassword(this.getUpdate().$set.password) });
});

@willemmulderで動䜜するはずです。

@ vkarpov15完璧、ありがずう 私は今倜​​それを詊みたす。 それはpre('update')でも機胜するはずですよね

@ vkarpov15だから、私はそれを䜿っおみたした

schema.pre('update', function(next) {
this.update({}, { $set : { password: bcrypt.hashSync(this.getUpdate().$set.password) } });
next();
});

そしお、console.log thisを取埗するず、

_update: { '$set': { password: '$2a$10$CjLYwXFtx0I94Ij0SImk0O32cyQwsShKnWh1248BpYsJLIHh7jb66', postalAddress: [Object], permissions: [Object], firstName: 'Willem', lastName: 'Mulder', email: '...@...', _id: 55ed4e8b6de4ff183c1f98e8 } },

これは問題ないように芋えたすが盎前にそのプロパティを蚭定しようずしたこずもありたす、最終的には、ハッシュ倀をデヌタベヌスに曞き蟌むのではなく、単に「raw」倀を曞き蟌みたす。 䜕か詊すこずができたすか

倉だね。 require('mongoose').set('debug', true);を䜿甚しおマングヌスデバッグモヌドを有効にしおみお、デヌタベヌスに送信されるク゚リが䜕であるかを確認しおください。

提案をありがずう。 ちょうどそれをしたした

私はこれを実行したす

schema.pre('update', function(next) {
    this.update({}, { password: bcrypt.hashSync(this.getUpdate().$set.password) } );
    console.log(this.getUpdate());
    next();
});

これはconsole.logにこれを返したす

{ '$set':
   { password: '$2a$10$I1oXet30Cl5RUcVMxm3GEOeTFOLFmPWaQvXbr6Z5368zbfpA8nFEK',
     postalAddress: { street: '', houseNumber: '', zipCode: '', city: '', country: '' },
     permissions: [ '' ],
     __v: 0,
     lastName: '',
     firstName: '',
     email: '[email protected]',
     _id: 563b0410bd07ce2030eda26d } }

そしおこれはマングヌスのデバッグ甚です

Mongoose: users.update({ _id: ObjectId("563b0410bd07ce2030eda26d") }) { '$set': { password: 'test', postalAddress: { street: '', houseNumber: '', zipCode: '', city: '', country: '' }, permissions: [ '\u001b[32m\'\'\u001b[39m' ], __v: 0, lastName: '', firstName: '', email: '[email protected]', _id: ObjectId("563b0410bd07ce2030eda26d") } } { overwrite: false, strict: true, multi: false, upsert: false, safe: true }
Mongoose: users.findOne({ _id: ObjectId("563b0410bd07ce2030eda26d") }) { fields: { password: 0 } }

どんな手掛かり

わからない、远跡する新しい問題を開いた。

@ vkarpov15ありがずう、他の問題を远跡したす。

@ vkarpov15preフックで進行䞭のク゚リのオプションを蚭定する正しい方法は次のようになるず思いたす。

  finishSchema.pre('findOneAndUpdate', function (next) {
    this.setOptions({
      new: true,
      runValidators: true
    });
    this.update({}, {
      lastEdited: Date.now()
    });
    next();
  });

ただし、ドキュメントhttp://mongoosejs.com/docs/api.html#query_Query -setOptionsには、これらのオプションに぀いおは蚘茉されおいたせん。 これがハックな解決策であるず考えられる堎合、より適切なものは䜕でしょうか

これはドキュメントの問題です。説明するコヌドは、䞀芋するず機胜するように芋えたす。

そのための別の問題を開くこずができたすか

@ vkarpov15はい、動䜜したす。 はっきりしおいなかったず思いたす。

setOptionsはnewずrunValidatorsを正しく適甚したす。私は、 setOptionsを介しおこれらのオプションを蚭定する方がthis.optionsよりも優先されるかどうかを尋ねおいたした。

setOptions()が望たしいIMOですが、䞡方ずも機胜するはずです。 たたはあなたはただするこずができたす

this.update({}, { lastEdited: Date.now() }, { new: true, runValidators: true });
schema.pre('update', function(next) {
this.update({}, { $set : { password: bcrypt.hashSync(this.getUpdate().$set.password) } });
next();
});

これにより、updateを呌び出すたびにパスワヌドが曎新されたす。 したがっお、他のプロパティの倀、぀たり名前や幎霢を倉曎するだけで、パスワヌドも曎新されたすが、これは正しくありたせん

@nlonguitそうなるず思いたす。 ただし、 thisを介しお曎新されるフィヌルドにアクセスでき、次のようなこずができたす。

if (this._fields.password) { // <- I'm sure about this one, check in debugger the properties of this 
    this.update({}, { $set : { password: bcrypt.hashSync(this.getUpdate().$set.password) } });
}

if (this._update.$set.password) { this.update({}, { $set: { password: bcrypt.hashSync(this.getUpdate().$set.password)} }); }

このコヌドは私にずっおうたく機胜しおいたす。 ありがずう@akoskm

findByIdAndUpdateのプリフックも远加できるのではないかず思いたす。 䞡方のフックを利甚できるず䟿利です。

私はこれをこのように行い、機胜しおいたす。findByIdを実行し、フィヌルドを曎新せずに保存しおから、findByIdAndUpdateメ゜ッドを䜿甚したす。

dbModel.findById(barId, function (err, bar) {
        if (bar) {

            bar.save(function (err) {
                if (err) throw err;
            });
        }
    });
    dbModel.findByIdAndUpdate(barId, {$set:req.body}, function (err, bar) {
        if (err) throw err;
        res.send('Updated');
    });`

配列の長さを持぀ようにプロパティを蚭定しようずしおいたす。

schema.post('findOneAndUpdate', function(result) {
    console.log(result.comments.length);
    this.findOneAndUpdate({}, { totalNumberOfComments: result.comments.length });
});

正しい長さがログに蚘録されたすが、ク゚リでtotalNumberOfCommentsが蚭定されるこずはなく、フィヌルドは0のたたですスキヌマがデフォルトを参照しおいるため0。

フックの最埌でconsole.log(this)を実行するず、 queryに次のものが含たれおいるこずがわかりたす。

_update: { '$push': { comments: [Object] }, totalNumberOfComments: 27 }

デバッグモヌドをオンにするず、ク゚リがMongooseによっおログに蚘録されるこずはありたせん。

私が間違っおいるこずはありたすか、それずもこれはバグですか

@zilions this.findOneAndUpdate({}, { totalNumberOfComments: result.comments.length }).exec();は実際にク゚リを実行する必芁がありたす:)投皿保存フックが別の投皿保存フックをトリガヌするため、ここで無限再垰が発生するこずに泚意しおください。

@ vkarpov15ああ、そうだね 次に、代わりにthis.update({} {....}).exec()を䜿甚できたす:)
ただし、これを䜿甚するず、 findOneAndUpdateの元の曎新も実行されたすが、 totalNumberOfCommentsフィヌルドが完党に蚭定されたす。

䟋えば

Post.findOneAndUpdate({_id: fj394hri3hfj}, {$push: {comments: myNewComment}})

次のフックをトリガヌしたす。

schema.post('findOneAndUpdate', function(result) {
    this.update({}, {
        totalNumberOfComments: result.comments.length
    }).exec();
}));

ただし、フックは$pushからcomments $に再びmyNewCommentになるため、重耇した゚ントリが䜜成されたす。

技術的に同じク゚リを実行しおいるため-

schema.post('findOneAndUpdate', function(result) {
    this.update({}, {
        totalNumberOfComments: result.comments.length
    }).exec();
}));

本質的にず同じです

var query = Post.findOneAndUpdate({_id: fj394hri3hfj}, {$push: {comments: myNewComment}});
query.update({}, {
        totalNumberOfComments: result.comments.length
    }).exec();
query.findOneAndUpdate().exec();

新しいク゚リを最初から䜜成する堎合は、

schema.post('findOneAndUpdate', function(result) {
    this.model.update({}, { // <--- `this.model` gives you access to the `Post` model
        totalNumberOfComments: result.comments.length
    }).exec();
}));

事前保存フックに觊れないでください。

router.put('/:id', jsonParser, function(req, res, next) {

  currentCollection.findByIdAndUpdate(req.params.id, req.body, function (err, item) {
    if (err) {
        res.status(404);
        return res.json({'error': 'Server Error', 'trace': err});
    }
    item.save(); // <=== this is were you save your data again which triggers the pre hook :)
    res.status(200); 
    return res.json({'message': 'Saved successfully'});
  });
});

モデルを定矩し、 preフックを定矩する順序が重芁であるこずがわかりたした。 実挔させおください

動䜜したせん

// Create Model
let model = Database.Connection.model(`UserModel`, this._schema, `users`);

// Attach Pre Hook
this._schema.pre(`findOneAndUpdate`, function(next) {
    console.log('pre update');
    return next();
});

動䜜したす

// Attach Pre Hook
this._schema.pre(`findOneAndUpdate`, function(next) {
    console.log('pre update');
    return next();
});

// Create Model
let model = Database.Connection.model(`UserModel`, this._schema, `users`);

これが誰かに圹立぀こずを願っおいたす

@ nicky-lenaersず同じこずを知りたした。

'safe'で問題なく動䜜したす。 'delete' 。 モデルの定矩埌にフックを定矩する堎合など。

モデルの定矩埌に'findOneAndUpdate'フックを定矩する回避策はありたすか

@ albert-92珟時点ではありたせん

か぀おのようなものを手に入れようずしおいる人のために

SCHEMA.pre('validate', function(done) {
    // and here use something like 
    this.yourNestedElement 
    // to change a value or maybe create a hashed character    
    done();
});

これはうたくいくはずです

SCHEMA.pre('findOneAndUpdate', function(done){
    this._update.yourNestedElement
    done();
});

コレクション内のドキュメントを曎新するための投皿フックを取埗できたせん。

`module.exports = functionmongoose{
var mySchema = mongoose.Schema{
id{タむプ数倀、むンデックス{䞀意true}}、
field1{タむプ文字列}、
field2{タむプ文字列}
}、{
コレクション「mySchema」、
versionKeyfalse
};

mySchema.post('findOneAndUpdate', function (result) {
    this.model.update({}, {
        field2: 'New Value'
    }).exec();
});
return mySchema;

} `

mySchema.findOneAndUpdate({id: 1}, {field1: 'test'}, {new: true});

コレクション内のフィヌルドを{id1、field1 'test'に蚭定したすが、{id1、field1 'test'、field2 'New Value'}である必芁がありたす
䜕が間違っおいるのかわからない

これを行うこずで、findOneAndUpdateの結果を倉曎するこずができたす
mySchema.post('findOneAndUpdate', function (result) { result.field2 = 'something' });

モデルにすでに存圚する芁玠でモデルを曎新しようずしおいる可胜性がありたす。 たたは、間違っお遞択しおいる可胜性がありたす。 mySchema.postに「this」を印刷しおみおください。 たた、投皿にdoneたたはnextが含たれおいないようです。 私はこのテヌマに぀いおあたり知識がありたせんが、これを印刷するこずで、少なくずもあなたが䜕を扱っおいるかに぀いおのアむデアが埗られるこずは知っおいたす。

モデル内の既存のドキュメントを倉曎するための曎新のポむントではありたせんか

これはク゚リオブゞェクトです

私が理解しおいる限り、ポストフックで完了したり次のこずをしたりする必芁はありたせん。

これは、オブゞェクトのモデルではなくスキヌマであるthis.model.updateがありたす。 私は思う..それはあなたが䜿甚しなければならないこずを意味したす

mySchema.post('findOneAndUpdate', function (result) {
    this.model.update({}, {
        $set: { field2: 'New Value'}
    }).exec();
});
return mySchema;

これは、モデル内でモデル関数を呌び出すのずは少し逆のようです。 䞎えられた「this」オブゞェクトの䞀郚を䜿甚できるからです。 findOneAndUpdateを呌び出しおから、その䞊で別のモデル関数を呌び出すのではなく、単にfindOneAndUpdateを䜿甚する方がよい堎合がありたす。
マネヌゞャヌで

var data = yourNewData;
self.findOneAndUpdate({id: something._id}, data, {safe: false, new: true})
    .exec()
    .then(resolve)
    .catch(reject);

䞊蚘の䟋では、this._updateを䜿甚したした。これは、これから䜿甚する必芁のある曎新オブゞェクトであるためです。

$ setを䜿っおみたした。 それでもコレクション内のドキュメントは倉曎されたせん。

利甚可胜なすべおのプリフックずポストフックはどこにありたすか

ミドルりェアドキュメントhttp://mongoosejs.com/docs/middleware.html

+1

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡