2013-02-06 10 views
8

最近MongoDBを使い始めましたが、文書の配列の更新に関する質問があります。 私はこのような構造を持って:私は次のクエリを実行しようとしているMongoDBは配列の複数のレコードを更新します

{ 
"_id" : ObjectId(), 
"post" : "", 
"comments" : [ 
     { 
       "user" : "test", 
       "avatar" : "/static/avatars/asd.jpg", 
       "text" : "....." 
     } 
     { 
       "user" : "test", 
       "avatar" : "/static/avatars/asd.jpg", 
       "text" : "....." 
     } 
     { 
       "user" : "test", 
       "avatar" : "/static/avatars/asd.jpg", 
       "text" : "....." 
     } 
     ... 
    ] 
} 

update({"comments.user":"test"},{$set:{"comments.$.avatar": "new_avatar.jpg"}},false,true) 

問題は、それがすべての文書を更新することですが、それはすべての中だけで最初の配列要素を更新資料。すべての配列要素を更新する方法はありますか、それとも手動で行うべきですか?おかげさまで

答えて

19

1回の更新操作で複数の配列要素を変更することはできません。したがって、複数の配列要素を変更する必要があるドキュメントを移行するには、更新を繰り返す必要があります。あなたは、例えば、文書はその関連するコメントのすべてを交換するまで繰り返し$elemMatchでアップデートを適用して、コレクション内の各ドキュメントを反復処理することによってこれを行うことができます。

 
db.collection.find().forEach(function(doc) { 
    do { 
    db.collection.update({_id: doc._id, 
          comments:{$elemMatch:{user:"test", 
               avatar:{$ne:"new_avatar.jpg"}}}}, 
         {$set:{"comments.$.avatar":"new_avatar.jpg"}}); 
    } while (db.getPrevError().n != 0); 
}) 

注意この作業の効率がための要件である場合は、そのスキンを正規化して、ユーザーのアバターの場所がすべてのコメントではなく単一のドキュメントに保存されるようにする必要があります。

+0

答えに感謝します。まあ、mongoには参加していないので、私はコメント付きでブログシステムを作りたいと思っています。私は彼のコメントの隣にすべてのユーザーのアバターを見せたいと思います。どのように私のスキーマを構造化すべきですか? –

+0

概念的には、ユーザー=>アバターマップをどこかに保存する必要があります。各ユーザーのアバターをユーザー文書(ユーザーコレクション内)に保存することもできますし、特定のブログエントリのコメント作成者用のユーザー=>アバターマップをブログエントリのドキュメントのフィールドに保存することもできます。 MongoDBでの正規化の軽度の扱いについてはhttp://docs.mongodb.org/manual/applications/database-references/、http://docs.mongodb.org/manual/use-cases/storing-comments/を参照してください。 "ユーザーのコメント"ユースケース分析。 –

+0

ええ、あなたの答えを見た直前に解決策を見つけました。とにかく@Jasonさん、ありがとう。 –

5

forEachで使用する関数を作成して評価する方法があります(そのため、すぐに実行されます)。

var runUpdate = function(){ 
    db.article.find({"comments.user":"test").forEach(function(article) { 
     for(var i in article.comments){ 
      article.comments[i].avatar = 'new_avatar.jpg'; 
     } 
     db.article.save(article); 
    }); 
}; 

db.eval(runUpdate); 
-1

あなたがこれを行うことができますように思える:

db.yourCollection.update({"comments.user":"test"},{$set:{"comments.0.avatar": "new_avatar.jpg", "comments.1.avatar": "new_avatar.jpg", etc...}) 

あなたは配列要素の小さな既知の数を持っているのであれば、これを行うために少し楽かもしれません。あなたが "コメント。*。アバター"のようなものを望むなら、それをどうやって行うかわからない。あなたがこのような問題なくこれを行うことができます更新したいインデックスを知っていればあなたは...

1

カントーそんなにデータの重複を持っていることを、おそらく良いことではありません。

var update = { $set: {} }; 
for (var i = 0; i < indexesToUpdate.length; ++i) { 
    update.$set[`comments.${indexesToUpdate[i]}. avatar`] = "new_avatar.jpg"; 
} 
Comments.update({ "comments.user":"test" }, update, function(error) { 
    // ... 
}); 
  • は注意してくださいIDEの必要条件は構文を受け入れませんが、無視することができます。
関連する問題