2017-09-05 8 views
3

このクエリは機能しますが、ドキュメント全体にはnetwork.stations.$が表示されます。 fields: network.stations.$と書くとエラーになります。ドキュメントで[stations]の単一の要素のみを返す方法はありますか?

Network.findOneAndUpdate({ 
    "network.stations.id": req.params.station_Id 
}, { 
    "network.stations.$.free_bikes": req.body.free_bikes 
}, { 
    new: true, 
    fields: "network.stations" 
}, (err, doc) => console.log(doc)) 
// I want doc to somehow point only to a single station instead of 
// several stations like it currently does. 

答えて

1

回答は「はい」ですが、期待しているとおりではありません。

"cannot use a positional projection and return the new document"

あなたが本当に「必要がないので、これはしかし、「ヒント」である必要があります:あなたは、位置的に「改変」文書は、特定のエラーをスロー返すため"fields"オプションでnetwork.stations.$を入れて、質問に注意したよう"あなたが値を知っているときに"新しい文書 "を変更しています。単純なケースでは、"new"ドキュメントを返しませんが、代わりに、 "原子の変更前"である "見つかった状態"を返し、ステートメントでの適用を要求したときと同じように返されたデータを変更します。

const mongoose = require('mongoose'), 
     Schema = mongoose.Schema; 

mongoose.Promise = global.Promise; 
mongoose.set('debug',true); 

const uri = 'mongodb://localhost/test', 
     options = { useMongoClient: true }; 

const testSchema = new Schema({},{ strict: false }); 

const Test = mongoose.model('Test', testSchema, 'collection'); 

function log(data) { 
    console.log(JSON.stringify(data,undefined,2)) 
} 

(async function() { 

    try { 

    const conn = await mongoose.connect(uri,options); 

    await Test.remove(); 

    await Test.insertMany([{ a: [{ b: 1 }, { b: 2 }] }]); 

    for (let i of [1,2]) { 
     let result = await Test.findOneAndUpdate(
     { "a.b": { "$gte": 2 } }, 
     { "$inc": { "a.$.b": 1 } }, 
     { "fields": { "a.$": 1 } } 
    ).lean(); 

     console.log('returned'); 
     log(result); 

     result.a[0].b = result.a[0].b + 1; 
     console.log('modified'); 
     log(result); 

    } 

    } catch(e) { 
    console.error(e) 
    } finally { 
    mongoose.disconnect() 
    } 


})(); 

生成します:

Mongoose: collection.remove({}, {}) 
Mongoose: collection.insertMany([ { __v: 0, a: [ { b: 1 }, { b: 2 } ], _id: 59af214b6fb3533d274928c9 } ]) 
Mongoose: collection.findAndModify({ 'a.b': { '$gte': 2 } }, [], { '$inc': { 'a.$.b': 1 } }, { new: false, upsert: false, fields: { 'a.$': 1 } }) 
returned 
{ 
    "_id": "59af214b6fb3533d274928c9", 
    "a": [ 
    { 
     "b": 2 
    } 
    ] 
} 
modified 
{ 
    "_id": "59af214b6fb3533d274928c9", 
    "a": [ 
    { 
     "b": 3 
    } 
    ] 
} 
Mongoose: collection.findAndModify({ 'a.b': { '$gte': 2 } }, [], { '$inc': { 'a.$.b': 1 } }, { new: false, upsert: false, fields: { 'a.$': 1 } }) 
returned 
{ 
    "_id": "59af214b6fb3533d274928c9", 
    "a": [ 
    { 
     "b": 3 
    } 
    ] 
} 
modified 
{ 
    "_id": "59af214b6fb3533d274928c9", 
    "a": [ 
    { 
     "b": 4 
    } 
    ] 
} 

をですから、更新が実際にサーバーに適用されていることを見ることができますので、私は、ループ内の変更をやっている小さな含まれているデモとして

次の反復は既にインクリメントされた値をインクリメントする。

"new"オプションを省略しただけでは、「適合」した状態のドキュメントが得られ、変更前にそのドキュメントの状態を返すことが完全に有効です。修正はまだ発生します。

ここで行う必要があるのは、コード内で同じ変更を行うだけです。 .lean()を追加すると、これは簡単になります。また、「サーバーに何を依頼したかを知っているから」再び完全に有効です。

これは、別々のクエリよりも優れています。これは、ドキュメントを「別個に」、修正とクエリの間の別の更新によって修正して、投影された一致フィールドのみを返すことができるからです。

そして、すべての要素を戻して後でフィルタリングするよりも、潜在的に「非常に大きな配列」になる可能性があります。もちろん、これは実際にはそうです。

0

projectionfieldsを変更してみてください、その後、あなたが前に試したようnetwork.stations.$を使用しています。

クエリが正常に機能している場合は、これで十分です。それでも動作しない場合は、2番目の引数を明示的に$setに変更してみてください。

Network.findOneAndUpdate({ 
    "network.stations.id": req.params.station_Id 
}, { 
    "$set": { 
    "network.stations.$.free_bikes": req.body.free_bikes 
    } 
}, { 
    new: true, 
    projection: "network.stations.$" 
}, (err, doc) => console.log(doc)) 
+0

'' projection ''は、[' '.findOneAndUpdate()']のMongoDB "コアドライバ"バージョンのオプションです(https://docs.mongodb.com/v3.2/reference/method/db.collection)。 .findOneAndUpdate /)。 ["mongoose method"](http://mongoosejs.com/docs/api.html#model_Model.findOneAndUpdate)には異なる署名があります。コアドライバでも、変更されたドキュメントから位置投影を返すことはできません。 –

+0

$ setとprojectionプロパティが機能しませんでした。 –

+0

また、あなたが調べた構文も実際には "シェル"構文であることに注意してください。そして '' new "'はシェルにとって有効なオプションではなく、むしろ 'returnNewDocument'になります。そして、「ノードドライバメソッド」(http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#findOneAndUpdate)には、 'returnOriginal'というオプションの別の名前があります。もちろん、 "逆"ブール条件です。 「新規文書」を含む位置投影は機能しません。これは私の答えで説明されているものです。 –