MongoDB嵌入式对象没有ID(空值)

时间:2012-06-29 01:48:07

标签: java spring mongodb spring-data

我对使用Spring Data的MongoDB有疑问。 我有这些域类:

@Document
public class Deal  {
    @Id
    private ObjectId _id;
    private Location location;
    private User user;
    private String description;
    private String title;
    private String price;
    private boolean approved;
    private Date expirationDate;
    private Date publishedDate;
}

@Document
public class Location {
    @Id
    private ObjectId _id;
    private Double latitude;
    private Double longitude;
    private String country;
    private String street;
    private String zip;
}

@Document
public class User {
    @Id
    private ObjectId _id;
    private String email;
    private String password;
    private String profile_image_url;
    private Collection<Deal> deals = new ArrayList<Deal>();
}

通过这些域名,我可以成功CRUD。只有一个问题。保存具有交易的用户时,将交易和位置在将它们保存到MongoDB时将其设置为空。 为什么MongoDB不能为嵌入对象生成唯一的id?

用一笔交易保存用户后的结果:

{ "_id" : ObjectId( "4fed0591d17011868cf9c982" ),
  "_class" : "User",
  "email" : "milo@gmail.com",
  "password" : "mimi",
  "deals" : [ 
    { "_id" : null,
      "location" : { "_id" : null,
        "latitude" : 2.22,
        "longitude" : 3.23445,
        "country" : "Denmark",
        "street" : "Denmark road 77",
        "zip" : "2933" },
      "description" : "The new Nexus 7 Tablet. A 7 inch tablet from Google.",
      "title" : "Nexus 7",
      "price" : "1300",
      "approved" : false,
      "expirationDate" : Date( 1343512800000 ),
      "publishedDate" : Date( 1340933521374 ) } ] }

从结果中可以看出,Deal和Location ID设置为NULL。

5 个答案:

答案 0 :(得分:35)

MongoDB CRUD操作(insertupdatefindremove)都专门在顶级文档上运行 - 当然,您可以按字段过滤嵌入式文件。嵌入式文档始终在父文档中返回。

_id字段是父文档的必填字段,通常不是必需的或存在于嵌入式文档中。如果您需要唯一标识符,您当然可以创建它们,如果方便您的代码或心智模型,您可以使用_id字段来存储它们;更典型地,它们以它们代表的内容命名(例如“username”,“otherSystemKey”等)。除了顶级文档之外,MongoDB本身和任何驱动程序都不会自动填充_id字段。

特别是在Java中,如果您希望为嵌入式文档中的_id字段生成ObjectId值,可以使用以下命令:

someEmbeddedDoc._id = new ObjectId();

答案 1 :(得分:6)

默认情况下,仅在根文档上没有在子文档上设置_id。

您需要在插入和更新时为子文档定义_id。

答案 2 :(得分:5)

在REST架构的上下文中,嵌套文档具有自己的ID是很有意义的。

  1. 持久性实现应独立于资源表示。作为API使用者,我不在乎您是否使用mongo或mysql。如果你在mongo中没有id的嵌套文档试着想象如何将持久层更改为关系数据库。现在做一个事先考虑过与实现无关的方法的练习。在关系数据库,根和嵌套文档中对嵌套文档建模将是不同的实体/表,每个实体/表都有自己的ID。 root可以与嵌套doc有一对多的关系。
  2. 我可能需要直接访问嵌套文档而不是顺序访问。我可能不需要绝对唯一ID,如mongo发布的那些,但我仍然需要一些本地唯一标识符。这在根文档中是唯一的。
  3. 在嵌套文档中讨论了关于id的需求的观点@dcrosta已经就如何在mongo中填充_id字段给出了正确的答案。

    希望这有帮助。

答案 3 :(得分:4)

Mongo不会在嵌入式文档上创建或需要_id。如果您愿意,可以添加_id字段 - 我已经完成了。

@Document
public class Location {
    @Id
    private ObjectId _id;

    public Location() {
        this._id = ObjectId.get();
    }
}

@Document
public class User {
    @Id
    private ObjectId _id;

    public User() {
        this._id = ObjectId.get();
    }
}

这对我很有用。

答案 4 :(得分:0)

其他答案现在不再适用。每个子文档都会自动获得一个 _id。 实际上,为了避免将 _id 应用于子文档,您必须显式传递选项

{ _id: false }

在子文档架构中。