Spring数据mongodb查询自动将String转换为ObjectId

时间:2013-01-15 20:12:11

标签: java mongodb spring-data

标题可能不是很清楚,这里是问题

我正在以这种形式执行更新:

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

仅当没有具有相同userid的文档时,才在文档中插入文档(解决方法,因为唯一索引不适用于数组)。代码在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使用ObjectId而不是String。

有什么想法吗?

更新

这是投票类

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中的Userid推送为String,但相同的String将作为$ ne中的ObjectId进行比较

1 个答案:

答案 0 :(得分:2)

在我看来,问题可以这样描述:如果你在类中使用String代替ObjectId,如果你想在其他文档(和嵌入文档)中使用这些id作为引用(没有dbrefs),它们被推送为String(没关系,因为它们是字符串)。这很好,因为spring数据可以将它们再次映射到objectid,但是如果你像我提到的那样进行查询则不行;该字段在比较中转换为objectid(在本例中为$ ne运算符),但在嵌入文档中被视为字符串。因此,总结一下,在我看来,在这种情况下,$ ne运算符应该将字段视为字符串。

我的解决方案是编写一个自定义转换器,将String作为objectid存储在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;
  }
}