2017-08-25 6 views
0

文書のicon属性を更新するためにpre('findOneAndUpdate')を使用しようとしています。更新は、yearlymeeting属性の既存の値に基づいています(下記参照)。Mongoose( 'findOneAndUpdate')ミドルウェア:オリジナル文書へのアクセスが必要

prepostsave()フックがupdate()上で実行されていないので、私はすべて元の文書にアクセスすることができないように見えます。しかし、これは私が実行しようとしている操作にとって非常に重要です。これを回避する方法はありますか?

例えば、私はそうのように、pre('save')に私の目的を達成することができる午前:私は理解して

meetingSchema.pre('findOneAndUpdate', function(next) { 
    const yearlymeetingSlug = originalDocument.yearlymeeting[0].toLowerCase().replace(/[^A-z0-9]/g, ''); 
    this.icon = `${yearlymeetingSlug}.png` 
    next(); 
}); 

:私は行うことができるようにしたいと思い何

meetingSchema.pre('save', function(next) { 
    const yearlymeetingSlug = this.yearlymeeting[0].toLowerCase().replace(/[^A-z0-9]/g, ''); 
    this.icon = `${yearlymeetingSlug}.png` 
    next(); 
}); 

はこのようなものですプレフィックス(findOneAndUpdate)のthisは、格納されたドキュメント自体ではなく、クエリを参照します。文書にアクセスする方法はありますか?そのため、yearlymeetingの保存値に基づいてiconを更新できますか?

+0

あなたが理解していれば、 "ドキュメント"は変更点で "サーバ"上にあることを理解するでしょう。したがって、 "クライアント"上のライブラリ機能がドキュメントを変更することはできません。 '.findOneAndUpdate()'は、実際に命令で送信している「現在のデータ」のみを認識します。フィールドコンテンツが既にクライアント上にある場合は、オプションを '$ set'などに入力する前に変更を加えます。あなたがそのデータを持っていない場合は、代わりにサーバから取得する必要があります。 MongoDBが既存の値 –

答えて

2

tl; dr

ミドルウェアでは使用できません。最初にドキュメントのクエリを実行し、特定のバージョンのドキュメントを競合状態を避けるために個別に更新します。設計では

- 更新された文書であっても、サーバーのメモリにではないかもしれません。


はそれをあなたがthis issue on the Mongoose Github (from the main dev)に従ってしようとしている方法を行うことはできません。そのためには、mongooseは、update()を実行する前にドキュメントをロードするためにfindOne()を実行する必要がありますが、これは受け入れられません。

フィルタ、更新パラメータ、オプションなどを追加または削除することで、クエリオブジェクトを操作できるように設計されています。たとえば、find()およびfindOne()で.populate()を自動的に呼び出し、特定のモデル、アクセス制御、およびその他の可能性については、デフォルトで真のオプションです。

findOneAndUpdate()は誤った名前で、基本的なmongodb findAndModifyコマンドを使用しますが、findOne()+ update()と同じではありません。別の操作として、独自のミドルウェアが必要です。

これに続いて、ミドルウェア自体の元のドキュメントにアクセスするための問題スレッドには他に提案はありません。

これまでに何度も何度もやらなければならなかったことは、ドキュメントを更新する前にクエリを実行するだけです(もちろん、誰に応じて競合状態に陥る可能性がありますかドキュメントの更新、そして時に、しかし、あなたはまた、ドキュメントの特定のバージョンを照会することによって、その問題を解決することができている - )、「楽観的ロック」の一種:

let meeting = yield Meeting.findOne({}).exec() 
let update = {} 

// ... some conditional logic to figure out which icon to set 
update.icon = // whatever 

yield Meeting.update({ _id: meeting._id, version: meeting.version }, update) 

これはもちろんですが、あなたが "持っていると仮定しますあなたのスキーマの「バージョン」フィールドに入力します。この種のロックにより、古いバージョンのドキュメントを更新できなくなります。このようなバージョン管理を使用する場合は、ドキュメントが更新/保存されるたびに、ドキュメントのバージョンを更新するミドルウェアを追加することもできます。

競合状況やリスクの可能性を認識している限り、ロックを使用しない、より純粋な実装を使用することもできます。

0

これは最適な解決策ではないかもしれませんが、私はそれを機能させる方法を見つけました。私はスキーマのプリフックではなくコントローラを使用しました。ここに、私の更新コントローラの外観を示します。

exports.updateMeeting = async (req, res) => { 
    const _id = req.params.id 
    let meeting = await Meeting.findOneAndUpdate({ _id }, req.body, { 
    new: true, 
    runValidators: true 
    }); 

    /* New Code: */ 
    const yearlymeetingSlug = meeting.yearlymeeting[0].toLowerCase().replace(/[^A-z0-9]/g, ''); 
    meeting.icon = `${yearlymeetingSlug}.png`; 
    meeting.save(); 

    req.flash('success', 'meeting successfully updated!'); 
    res.redirect(`/meetings/${meeting.slug}`); 
}; 

この解決策で表示される問題についてご意見をお待ちしております。

+1

'await meeting.save()'を参照する方法はありません。それはまだ非同期メソッドです。 –

関連する問題