2013-12-09 5 views
7

から一つだけの要素を引っ張る:

"userTags" : [ 
     "foo", 
     "foo", 
     "foo", 
     "foo", 
     "moo", 
     "bar" 
    ] 

私は私が正しく配列にfooの別のインスタンスを挿入することができdb.products.update({criteriaToGetDocument}, {$push: {userTags: "foo"}}}を実行する場合。しかし

、私はdb.products.update({criteriaToGetDocument}, {$pull: {userTags: "foo"}}}が、それは私を残して、配列からfooすべてのインスタンスを削除しない場合:

"userTags" : [ 
     "moo", 
     "bar" 
    ] 

これは全くしないだろう、私は唯一の1つの項目を引っ張るしたいですそれらのすべてではなく配列。 fooが1つだけ削除されるようにコマンドを変更するにはどうすればよいですか?ここで働くことができる$pullOnceメソッドのいくつかの種類はありますか?

答えて

4

いいえ、現時点ではこのようなものはありません。多くの人が既にこの機能をリクエストしており、mongodb Jiraでそれを追跡できます。あなたが見ることができる限り、それは解決されておらず、予定されていません(つまり、あなたは近い将来運がないことを意味します)。

唯一のオプションは、これは可能でしょう達成するためのアプリケーション・ロジックを使用することです:

  1. したい検索要素とそれがuserTagsを通じてfooの
  2. 反復としてuserTagsを持っており、それ
  3. から1つのFOOを削除その要素を新しいuserTagsで更新する

この操作ではアトミック性が損なわれますが、Mongoはネイティブメソッドを提供していないため、atomiどのような方法で都市。

私はこの質問に答えないので、新しい回答に1つの代替ソリューションを移しましたが、既存のスキーマをリファクタリングするアプローチの1つを表しています。それもまた大きくなり、元の答えよりはるかに大きくなり始めました。

+0

これは...非常に面倒です。 'userTags'は' {tag:(numberofinstances)} 'のオブジェクトで、必要に応じてこの数値を増減するだけですが、本当にむしろそれをやめてしまいます他のものの多くのwhooooleと! – Jascination

+0

私はあなたに同意します。この機能は本当に便利で、ドキュメントを読まなくても$ pullのアイデアを誤解する可能性があります。しかし、モンゴの人々は、すべてのリリース中にモンゴの機能を向上させる良い仕事をしています。だから私はいつかあなたが箱からこれを見ると信じています。 P.S. - JIRAの機能に対する投票。 –

+0

ニースの編集。タグが存在するかどうかをチェックし、それが1より大きいかどうかを確認するコマンドを提案できますか?あるいは、 'tag:{$ exists:true}'を1回の検索で見つけて、新しいタグ番号で更新する必要がありますか? – Jascination

1

本当にこの機能を使用する場合は、スキーマの変更を検討する必要があります。 1つの方法は、このような何かをすることです:

"userTags" : { 
    "foo" : 4, 
    "moo": 1, 
    "bar": 1 
} 

ここで、数字はタグの数です。この方法で、atomic $ incを使用してタグを追加または削除できます。新しいタグを追加することは適切ですが、タグを削除する際は注意が必要です。あなたはタグが存在することを確認する必要があり、それがあることを> =、その後1ここで

あなたがそれを行うことができますどのようにされています

:あなたはこの操作を行う必要があり

db.a.insert({ 
    _id : 1, 
    "userTags" : { 
    "foo" : 4, 
    "moo": 1, 
    "bar": 1 
    } 
}) 

つのタグを追加します

db.a.update({_id : 1}, {$inc : {'userTags.zoo' : 1}}) 

それはタグを削除するには、それを

を作成する前に、タグが存在していなかった場合、あなたはもう少しを実行する必要があります。

db.a.update({ 
    _id : 1, 
    'userTags.moo' : {$gte : 1 } 
}, { 
    $inc : {'userTags.moo' : -1} 
}) 

ここで要素が存在し、1より大きいかどうかを確認しています($ gteもこれを行っているため、存在を確認する必要はありません)。

この方法には欠点が1つあります。フィールドとしてリストされていても、実際のタグではない(値は0です)いくつかのタグを持つことができます。あなたは、出力要素のすべてのタグは、あなたは同じ問題を抱えているかもしれません。また

db.a.find({'userTags.zoo' : { $gte : 1}}) 

:だからあなたがタグfooの持つすべての要素を検索したい場合は、このことを覚えているし、このような何かをしなければなりません。したがって、アプリケーション層で出力をサニタイズする必要があります。私はこの同じ問題に遭遇したとして

0

私は、それが回避策ではなく、実際のソリューションです知っているが、私が見つかりました。PHPで、少なくとも、あなたはこのような何かを行うことができます。

// Remove up to two elements "bar" from an array called "foo" 
// in a document that matches the query {foo:"bar"} 

$un_bar_qty = 2; 
$un_bar_me = $db->foo->findOne(array("foo"=>"bar")); 
foreach($un_bar_me['bar'] as $foo => $bar) { 
    if($bar == 'bar') { 
     unset($un_bar_me['bar'][$foo]); 
     $un_bar_qty--; 
    } 
    if(!$un_bar_qty) break; 
} 
$db->foo->update(array('_id'=>$un_bar_me['_id']),$bar); 

ドキュメントの前に:

{ 
    { foo: "bar" }, 
    { bar: [ "bar" , "bar" , "foo", "bar" ] } 
} 

ドキュメントは、後:道の

{ 
    { foo: "bar" }, 
    { baz: [ "foo", "bar" ] } 
} 

あまりにも悪くないが、それを行うには。確かに、タグやインクリメントで悩まされるよりも、私にとって面倒なことはありませんでした.YMMV。

関連する問題