31

我有一个关于 MongoDB 和 Spring Data 的问题。我有这些域类:

@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 时将 _id 设置为 null。为什么 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 ) } ] }

从结果中可以看出,交易和位置 ID 设置为 NULL。

4

5 回答 5

51

MongoDB CRUD 操作 ( insert, update, find, remove) 都只对顶级文档进行操作——当然您可以按嵌入文档中的字段进行过滤。嵌入文档总是在父文档中返回。

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

特别是在 Java 中,如果您希望为_id嵌入文档中的字段生成 ObjectId 值,您可以这样做:

someEmbeddedDoc._id = new ObjectId();
于 2012-06-29T14:44:34.920 回答
8

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

  1. 持久性实现应该独立于资源表示。作为 API 使用者,我不在乎您使用的是 mongo 还是 mysql。如果您在 mongo 中没有 id 的嵌套文档,请尝试想象如何将持久层更改为关系数据库。现在做同样的练习,事先考虑过独立于实现的方法。在关系数据库中建模嵌套文档,根文档和嵌套文档将是不同的实体/表,每个都有自己的 id。根可能与嵌套文档具有一对多关系。
  2. 我可能需要直接访问嵌套文档而不是顺序访问。我可能不需要绝对唯一的 id,就像 mongo 发布的那样,但我仍然需要一些本地唯一标识符。这是根文档中唯一的。

在讨论了我关于嵌套文档中需要 id 的观点后,@dcrosta 已经就如何在 mongo 中填充 _id 字段给出了正确的答案。

希望这可以帮助。

于 2013-12-09T13:01:23.800 回答
7

Mongo 不会_id在嵌入式文档上创建或需要 s。如果需要,您可以添加一个_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();
    }
}

这对我很有用。

于 2012-10-10T15:55:58.887 回答
7

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

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

于 2012-06-29T07:51:39.680 回答
0

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

{ _id: false }

在子文档架构中。

于 2021-05-12T14:06:11.600 回答