2012-01-13 11 views
11

ドキュメントが存在しない場合は挿入する必要があります。私は "upsert"オプションがそれを行うことができることを知っていますが、私はいくつかの特別な必要があります。カスタム_id値を使用しているときにmongodbでアップサイズが発生する

まず、_idフィールドのみでドキュメントを作成する必要がありますが、ドキュメントがまだ存在しない場合にのみ作成する必要があります。私の_idフィールドは私によって生成された番号です(ObjectIdではありません)。私はその後、「アップサート」オプションを使用する場合、私は

db.mycollection.update({ _id: id }, { _id: id }, { upsert: true }); 

私たちは$セットに_idを使用できないことを知っている「のModは_idに許可されていません」を取得します。

私の質問は:「作成した場合、存在しない」という方法がmongodbに原子的に存在するかどうかです。

EDIT: @Barrieによって提案されたように、これは(nodejsとマングースを使用して)動作します。

var newUser = new User({ _id: id }); 
newUser.save(function (err) {    
    if (err && err.code === 11000) {    
      console.log('If duplicate key the user already exists', newTwitterUser); 
     return; 
    } 
    console.log('New user or err', newTwitterUser); 
}); 

しかし、それはそれを行うための最善の方法であれば、私はまだだろうか。

+0

'save'操作をしようとしていますか?つまり、db.collection.save({"_ id":your_id}) –

+0

既に存在する場合、重複キーエラーで保存に失敗します。 – aartiles

答えて

5

あなたはちょうどinsert()を使うことができます。あなたが指定した_idを持つドキュメントがすでに存在する場合、insert()は失敗し、何も変更されません。したがって、 "存在しない場合は作成する"は、作成された_id。

+0

意味があり、試しています。 – aartiles

+2

これは、文書が挿入後および後続の更新の前に削除される競合状態は依然として処理しません。 – Lucian

22

私は同じ問題を抱えていましたが、私のニーズに対してより良い解決策を見つけました。更新オブジェクトから_id属性を削除するだけで、同じクエリスタイルを使用できます。だから、最初にあなたがこれでエラーが出る場合:それは、挿入および更新の両方で動作しますので、これは良いです

db.mycollection.update({ _id: id }, {$set: { name: 'name' }}, { upsert: true }); 

db.mycollection.update({ _id: id }, {$set: { _id: id, name: 'name' }}, { upsert: true }); 

を代わりにこれを使用します。

+1

質問に記載されているように、これはObjectIDではない_idで動作しますか? –

+1

はい。 _idをObjectIDまたはカスタム値として使用すると、エラーが発生しました。したがって、常に '$ set'オブジェクトから_idを削除する必要があります。 –

+0

ありがとうございます。$ setオブジェクトから_idを削除するのは私の仕事です。 – ATilara

3

UPDATE:上記@Barrieによってexplaindよう_idとアップサートは、$setOnInsertことなく行うことができます。

$setOnInsert:{_id:1}のトリックは、upsertを使用することです。つまり、_idは挿入の場合にのみ書き込まれ、更新の場合は書き込まれません。

Only, there was a bug preventing this from working until v2.6 - 2.4で試したところ、うまくいきませんでした。

私が使用する回避策には、一意のインデックスを持つ別のIDフィールドがあります。例えば。 $setOnInsert:{myId:1}

+1

setOnInsertは私のために働いた。バリーの答えは、直接挿入は更新作業を行いませんが、ネイト・バーの答え、_idによる更新は検索基準を限定しました。私がしたいのは、db.coll.update({a:1、b:2}、{$ set:{c:3、d:4}、$ setOnInsert:{_id: 'xxxx'}}、{ upsert:true}) – vdonkey

0

$ setOnInsertは、単純なkey => valueオブジェクト($ setなどではない)をupsertすると簡単には機能しません。 私はそれを使用する必要があります(PHPで):

public function update($criteria , $new_object, array $options = array()){ 
    // In 2.6, $setOnInsert with upsert == true work with _id field 
    if(isset($options['upsert']) && $options['upsert']){ 
     $firstKey = array_keys($new_object)[0]; 
     if(strpos($firstKey, '$')===0){ 
      $new_object['$setOnInsert']['_id'] = $this->getStringId(); 
     } 
     //Even, we need to check if the object exists 
     else if($this->findOne($criteria, ['_id'])===null){ 
      //In this case, we need to set the _id 
      $new_object['_id'] = $this->getStringId(); 
     } 

    } 
    return parent::update($criteria, $new_object, $options); 
} 
関連する問題