2012-06-29 34 views
16

我有一個關於MongoDB和Spring Data的問題。 我有這些領域類:MongoDB嵌入式對象沒有ID(空值)

@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設置爲空。 爲什麼MongoDB不能爲嵌入對象生成唯一的ID?

節省了用戶與一個交易之後的結果:

{ "_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) } ] } 

你可以從結果看,交易,地點ID設置爲NULL。

+0

一個ID標識一個根文件,而不是子文件。沒有理由爲什麼你想爲嵌套文檔自動生成一個id,因爲MongoDB無論如何都只能檢索頂層文檔。你真的需要嵌套的ID爲什麼? –

+0

我需要搜索只有交易,而不是用戶。現在我必須從用戶搜索,然後循環以編程方式向用戶投擲每筆交易。 – Millad

+0

該ID與您可以搜索的內容無關。搜索'{'deals.price':{$ gt:1000}}'是非常好的。儘管如此,這個查詢會返回一個'User'對象,您必須手動從中取出'Deal'。這是一個MongoDB限制,Spring Data沒有暗示。 –

回答

4

缺省情況下,_id未在子文檔上設置,僅在根文檔上設置。

您需要在插入和更新時爲子文檔定義_id。

+0

他不應該那樣對我嗎?我怎樣才能做到這一點?我應該單獨插入每個文件並將它們放在一起嗎?這是我如何插入:mongoOperation.insert(deal); – Millad

+0

MongoDB不會爲你做這件事,但現在我再看一眼你的司機應該......你在使用Morphia嗎? – Sammaye

+0

感謝您的答覆。我正在使用Spring Data和mongo-java-driver。當我搜索交易時,我得到一個用戶對象。我無法使用交易進行搜索,我必須先投擲用戶,然後以編程方式在用戶中查詢交易。 – Millad

29

MongoDB的CRUD操作(insertupdatefindremove)都在頂層文件操作完全 - 雖然你當然可以通過嵌入文檔字段進行過濾。嵌入式文檔始終在父文檔中返回。

_id字段是父文檔的必填字段,通常不需要或不存在於嵌入式文檔中。如果你需要一個唯一的標識符,你當然可以創建它們,如果你的代碼或你的心智模型方便,你可以使用_id字段來存儲它們;更典型的是,它們以它們代表的內容命名(例如「用戶名」,「otherSystemKey」等)。 MongoDB本身和任何驅動程序都不會自動填充_id字段,但頂級文檔除外。

具體在Java中,如果你想生成嵌入文檔的_id領域的ObjectId值,你可以這樣做:

someEmbeddedDoc._id = new ObjectId(); 
+0

謝謝你解決這個問題。因此,如果我只想列出交易,我必須從交易文檔中分離或移動用戶文檔,以便交易是單獨的文檔,而用戶是分開的文檔,然後進行查詢。 – Millad

+0

或者調整您的代碼以使用現有的數據模型。如果您經常操縱交易,或者交易與多個用戶關聯,那麼對數據模型進行規範化可能是有意義的。 – dcrosta

2

蒙戈不產生或者需要嵌入文檔_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

在REST體系結構的上下文中,嵌套的文檔具有各自的ID。

  1. 持久性實現應該獨立於資源表示。作爲一個API消費者,我不在乎你使用的是mongo還是mysql。如果你在mongo中沒有id的嵌套文檔試圖想象如何將持久層更改爲關係數據庫。現在做一個事先考慮過的與獨立實現方法相同的練習。在關係數據庫,根和嵌套文檔中對嵌套文檔進行建模將是不同的實體/表,每個實體/表都有其自己的ID。根可能與嵌套文檔有一對多的關係。
  2. 我可能需要直接訪問嵌套的文檔,而不是按順序訪問。我可能不需要絕對唯一的id,就像mongo發佈的那樣,但我仍然需要一些本地唯一標識符。這在根文檔中是唯一的。

在論證嵌套文檔中id的必要性時,@dcrosta已經給出瞭如何在mongo中填充_id字段的正確答案。

希望這會有所幫助。