MongoDB Embedded Objects 没有 ID(空值)

2022-09-01 10:19:25

我有一个关于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。只有一个问题。保存包含成交的用户时,成交和位置_id保存到 MongoDB 时设置为 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。


答案 1

MongoDB CRUD操作(,,,)都只对顶级文档进行操作 - 尽管当然您可以按嵌入文档中的字段进行过滤。嵌入的文档始终在父文档中返回。insertupdatefindremove

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

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

someEmbeddedDoc._id = new ObjectId();

答案 2

在 REST 架构的上下文中,嵌套文档有自己的 ID 是有道理的。

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

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

希望这有帮助。