Встроенные объекты MongoDB не имеют идентификатора (нулевого значения)

У меня есть вопрос относительно MongoDB с данными Spring. У меня есть эти классы домена:

@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. Есть всего лишь одна проблема. При сохранении пользователя с предложениями, сделки и местоположение get_id устанавливаются равными нулю при сохранении их в MongoDB. Почему MongoDB не генерирует уникальные идентификаторы для встроенных объектов?

Результат после сохранения пользователя с одной сделкой:

{ "_id" : ObjectId( "4fed0591d17011868cf9c982" ),
  "_class" : "User",
  "email" : "[email protected]",
  "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 ) } ] }

Как вы можете видеть из результата, для параметра "Сделки и определения местоположения" установлено значение "NULL".

Ответ 1

Операции MongoDB CRUD (insert, update, find, remove) работают исключительно на документах верхнего уровня - хотя, конечно, вы можете фильтровать поля во встроенных документах. Встроенные документы всегда возвращаются в родительском документе.

Поле _id является обязательным полем родительского документа и обычно не является необходимым или присутствует во встроенных документах. Если вам нужен уникальный идентификатор, вы можете их создать, и вы можете использовать поле _id для их хранения, если это удобно для вашего кода или вашей ментальной модели; более типично они называются после того, что они представляют (например, "имя пользователя", "otherSystemKey" и т.д.). Ни сам MongoDB, ни любой из драйверов не будут автоматически заполнять поле _id, кроме документа верхнего уровня.

В частности, в Java, если вы хотите генерировать значения ObjectId для поля _id во встроенных документах, вы можете сделать это с помощью

someEmbeddedDoc._id = new ObjectId();

Ответ 2

_id не задается в поддокументах по умолчанию только на корневых документах.

Вам нужно будет определить _id для ваших поддокументов при вставке и обновлении.

Ответ 3

В контексте архитектуры REST все понимает, что вложенные документы имеют свои собственные идентификаторы.

  • Реализация настойчивости должна быть независимой от представления ресурсов. Как потребитель API, мне все равно, используете ли вы mongo или mysql. Если вы гнездо docs без id в mongo, попробуйте представить, как изменить уровень персистентности на реляционную базу данных. Теперь сделайте одно и то же упражнение, заранее подумав, используя независимый от реализации подход. Моделирование вложенных документов в реляционных db, корневых и вложенных документах будет представлять собой разные сущности/таблицы, каждый со своими идентификаторами. Корень может иметь отношение один-много к вложенному документу.
  • Мне может потребоваться доступ к вложенному документу напрямую, а не последовательно. Мне могут не понадобиться абсолютные уникальные идентификаторы, такие как те, которые выданы mongo, но мне по-прежнему нужен локальный уникальный идентификатор. Это уникально в корневом документе.

Оспорив мой вопрос о необходимости идентификаторов в вложенных документах @dcrosta уже дал правильный ответ о том, как заполнить поле _id в mongo.

Надеюсь, что это поможет.

Ответ 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();
    }
}

Это отлично работает для меня.