2013-01-07 112 views
20

Datomic Queries and Rules文檔的「嵌入式」部分說:獲取所有領域

查詢語言,如SQL圍繞着一個客戶端 - 服務器模型 面向地方,在一個單一的conversaton,你會要同時擁有:

  • 回答您的根本問題,例如誰在這個月買了襪子。
  • 恢復報告和處理所需的任何附加信息,例如他們的名字和電子郵件地址是什麼。

後者其實不是一個查詢,它只是一個機械導航 來相關的信息。

雖然我很欣賞這兩個不同方面的正交性,但我認爲我經常需要檢索一個完整的實體,無論其屬性如何。

據我所知,查詢通常有這樣的形式:

(datomic.api/q '[:find ?name ?age ?email 
       :where 
       [?e :myapp/name ?name] 
       [?e :myapp/age ?age] 
       [?e :myapp/email ?email]] 
       (db conn)) 

如果我想檢索有N個屬性的實體,我讓他們列出他們都在各自的查詢,這似乎有些單調乏味並且容易出錯。

如何告訴Datomic檢索包含所有字段的實體,而不必明確指定它們?

回答

7

datomic.api/entity提供了這樣的功能。

它只是有一個陷阱,返回的地圖有一個隱藏所有字段,但:db/id的自定義表示。可以訪問這些字段,但打印它們需要將地圖合併到常規的Clojure地圖中。

+2

一對夫婦的注意事項:(1)實體不「隱藏」屬性,它們是獲取實體屬性和相關實體的懶惰接口。從性能的角度來理解這一點非常重要,它解釋了爲什麼這些屬性並不都是立即可見的 - 它必須從數據庫中提取數據以顯示屬性,從而打敗懶惰的優勢。 (2)不需要將實體合併到地圖中,只需調用[touch](http://docs.datomic.com/clojure/#datomic.api/touch)函數即可獲得所有屬性。 – camdez

1

我沒有測試它,但如果我沒記錯的話你可以把一個變量作爲屬性名稱

(datomic.api/q '[:find ?key ?value 
      :where 
      [?e ?key ?value]] 
      (db conn)) 
+0

不確定您的查詢是否僅僅是一個存根,但會引發IllegalArgumentException,因爲它會導致完整的數據庫掃描 – vemv

+0

是的,通常您會通過添加一些有意義的where子句來限制實體,例如[?e:user/name「Joe 「] –

16

從查詢就像實體(ID):

=> (def eid (d/q '[:find ?e :where [?e :myapp/name "Fred"]] (db conn))) 

你可以得到EntityMap:

=> (def ent (d/entity (db conn) (ffirst eid))) 

所以你可以訪問字段/屬性而不需要額外的q uery:

=> (seq ent) 
;; ([:myapp/name "Fred"] [:myapp/age 16] [:myapp/email "[email protected]"]) 

但它可能會更容易先拿到鑰匙:

=> (keys ent) 
;; (:myapp/name :myapp/age :myapp/email) 

您甚至可以反向鍵使用下面的技巧(「洋」裁判屬性點這個實體):

=> (.touch ent) 
=> (keys (.cache ent)) 
+1

感謝您在答案中提供代碼示例! –

+1

鍵不適用於實體。 seq作品。 – haijin

7

datomic.api/touch功能

有一個特定datomic.api/touch功能只是「觸摸」實體的所有屬性。 Entityentity函數返回的函數是懶惰的,只有在訪問時才返回屬性值,touch函數急切地檢索所有的實體屬性。

例子:

(let [entity (d/entity db-val (ffirst (d/q '[:find ?e :in $ ?email 
              :where [?e :user/email ?email]] 
              db-val email))] 
    ;;then just d/touch the entity returned by the d/entity fn 
    (d/touch entity)) 
=> {:user/username "gretchen", :user/email "[email protected]", :user/password "xxxxxx", :db/id 17592186046433} 
6

您可以使用pull從實體得到的所有領域,甚至只是一個選擇。使用'[*]作爲拉模式將檢索所有字段

請參閱the pull documentation並進行說明。

要獲得從實體各領域的ID eid使用:

(d/pull (db conn) '[*] eid)

拉也可以在查詢中使用:

(datomic.api/q '[:find (pull ?e [*]) 
       :where 
       [?e :myapp/name] 
       (db conn)) 
+0

您不需要在':where'子句中的最後位置使用'_' - 該位置可以簡單地被忽略。即,'[?e:myapp/name]'。 –