【问题标题】:Spring data mongodb query converts String to ObjectId automaticallySpring data mongodb查询自动将String转换为ObjectId
【发布时间】:2012-12-30 00:59:11
【问题描述】:

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

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

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 使用 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

【问题讨论】:

  • 看来您在内部存储的 String 值可以是 ObjectIds。这是什么原因? String-to-ObjectId 转换的存在是为了能够在您的 Java 对象中使用 String 并且在数据库中仍然有 ObjectIds。
  • 也许我错过了一些东西。我使用字符串作为 User 对象的 _id;我的 Vote 对象有一个用户 ID 字符串字段,我将其用作对 User _id 的引用。数据库中的投票“字段”是一个文档数组。当我在这个数组中 $push 一个 vote.userid 时,我在数据库中有一个字符串,而不是一个 ObjectId。我将用一些代码更新我的帖子以使其更清晰。
  • 你没有说你使用的是什么版本的 Spring-data-mongodb。我最近在从 1.0.3 升级到 1.1.0 时被相反的情况所困扰,因为它们似乎已经取消了这种自动转换。我被咬了,因为我导出为 JSON 然后重新导入,留下“_id”:{“$id”:“4ee76418f3e1450f11000000”},这给了我 org.springframework.data.mapping.model.MappingException: No为 java.lang.String 找到的映射元数据。我不认为你可以同时拥有它
  • 这是 Spring Data Mongodb 1.2.0
  • 我面临类似的问题。如果我在高级文档中使用相同的字符串,则比较有效。但是如果我把它放在嵌套对象中,那么它会尝试进行 ObjectId 比较。很奇怪。否则,插入/查询时的行为也应该相同。一定是BUG。

标签: java mongodb spring-data


【解决方案1】:

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

我的解决方案是编写一个自定义转换器,将字符串作为 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;
  }
}

【讨论】:

    猜你喜欢
    • 2015-10-09
    • 2020-10-14
    • 1970-01-01
    • 1970-01-01
    • 2018-01-08
    • 2022-01-17
    • 1970-01-01
    • 2019-12-01
    • 1970-01-01
    相关资源
    最近更新 更多