6

タイトルはあまり明確ではないかもしれません、ここに問題があります

次の形式で更新を実行しています。

db.poi.update({
  _id: ObjectId("50f40cd052187a491707053b"),
  "votes.userid": {
    "$ne": "50f5460d5218fe9d1e2c7b4f"
  }
},
{
  $push: {
    votes: {
      "userid": "50f5460d5218fe9d1e2c7b4f", 
      "value": 1
    }
  },
  $inc: { "score":1 }
})

同じユーザー ID を持つドキュメントがない場合にのみ配列にドキュメントを挿入するには (一意のインデックスが配列では機能しないための回避策)。コードは mongo コンソールから正常に動作します。私のアプリケーションから、私はこれを使用しています:

@Override
public void vote(String id, Vote vote) {
    Query query = new Query(Criteria.where("_id").is(id).and("votes.userid").ne(vote.getUserid()));
    Update update = new Update().inc("score", vote.getValue()).push("votes", vote);
    mongoOperations.updateFirst(query, update, Poi.class);
}

これは、「userid」として mongo ObjectId にできない文字列を使用する場合は正常に機能しますが、例で文字列を使用すると、実行されたクエリは次のように変換されます (mongosniff から):

update  flags:0 q:{ _id: ObjectId('50f40cd052187a491707053b'), votes.userid: { $ne: ObjectId('50f5460d5218fe9d1e2c7b4f') } } o:{ $inc: { score: 1 }, $push: { votes: { userid: "50f5460d5218fe9d1e2c7b4f", value: 1 } } }

文字列は Objectid になりました。これはバグですか?BasicQuery も同じことを行います。私が見る他の唯一の解決策は、すべてのクラス ID に String の代わりに ObjectId を使用することです。

何かご意見は?

アップデート:

これは投票クラスです

public class Vote {
  private String userid;
  private int value;
}

これはユーザークラスです

@Document
public class User {

  @Id
  private String id;
  private String username;
}

これは、この更新を行っているクラスと mongo ドキュメントです。

@Document
public class MyClass {

  @Id
  private String id;
  @Indexed
  private String name;
  int score
  private Set<Vote>votes = new HashSet<Vote>();
}

Jsonとして

{
  "_id" : ObjectId("50f40cd052187a491707053b"),
  "name" : "Test",
  "score" : 12,
  "votes" : [
    {
      "userid" : "50f5460d5218fe9d1e2c7b4f",
      "value" : 1
    }
  ]
}

votes.userid のユーザー ID は文字列としてプッシュされますが、同じ文字列が $ne の ObjectId として比較されます。

4

1 に答える 1

2

問題は次のように説明できるように思えます: ObjectId の代わりにクラスで String を使用する場合、これらの ID を他のドキュメント (および埋め込みドキュメント) で参照 (dbref なし) として使用する場合、それらはプッシュされます。文字列として(文字列なので問題ありません)。spring data はそれらを objectid に再度マップできるので問題ありませんが、私が言及したようなクエリを実行しても問題ありません。フィールドは比較で objectid (この場合は $ne 演算子) に変換されますが、埋め込みドキュメントでは文字列と見なされます。まとめると、私の意見では、この場合の $ne 演算子はフィールドを文字列と見なす必要があります。

私の解決策は、IDが参照であるドキュメントに文字列をオブジェクトIDとして格納するカスタムコンバーターを作成することでした

public class VoteWriteConverter implements Converter<Vote, DBObject> {

  @Override
  public DBObject convert(Vote vote) {
    DBObject dbo = new BasicDBObject();
    dbo.put("userid", new ObjectId(vote.getUserid()));
    dbo.put("value", vote.getValue());
    return dbo;
  }
}
于 2013-01-16T11:22:52.047 に答える