Datomic - 使用OR子句

时间:2015-05-20 06:34:40

标签: clojure datomic

我目前正致力于将我的clojure应用程序(使用korma)迁移到Datomic框架,并在我翻译查询时处于循环中。我意识到查询不是完全灵活的(与korma相比),例如我想评估不同变量周围的条件子句。

考虑korma查询,

(select users
   (where (or (and {:first_name [= "user"]}
                   {:last_name [= "sample"]})
              {:email [= "user.sample@email.com"]})))

这可以转换为Datomic,有这样的东西吗?

 [:find ?e
  :where (or (and [?u :user/first-name "user"]
                  [?u :user/last-name "sample"])
             [?u :user/email "user.sample@email.com"])

但这不是推荐的查询方式(根据Datomic docs),因为or子句中使用的所有子句必须使用相同的变量集。如何围绕不同的变量集设置OR子句?

2 个答案:

答案 0 :(得分:7)

您的查询应该有效。您的所有子句使用相同的变量:?u

(d/q '[:find ?u
       :where (or (and [?u :user/first-name "user"]
                       [?u :user/last-name "sample"])
                  [?u :user/email "user.sample@email.com"])]
  [[1 :user/first-name "user"]
   [1 :user/last-name "sample"]
   [2 :user/email "user.sample@email.com"]
   [3 :user/first-name "user"]
   [3 :user/last-name "not sample"]])

=> #{[1] [2]}

如果您需要使用不同的变量,可以使用or-join明确列出它们:

(d/q '[:find ?u
       :in $ ?first-name ?last-name ?email
       :where (or-join [?u ?first-name ?last-name ?email]
                (and [?u :user/first-name ?first-name]
                     [?u :user/last-name ?last-name])
                [?u :user/email ?email])]
     [[1 :user/first-name "user"]
      [1 :user/last-name "sample"]
      [2 :user/email "user.sample@email.com"]
      [3 :user/first-name "user"]
      [3 :user/last-name "not sample"]]
     "user"
     "sample"
     "user.sample@email.com")

=> #{[1] [2]}

答案 1 :(得分:0)

这与这个问题非常相似:

SQL LIKE operator in datomic

您需要查看查询规则

http://docs.datomic.com/query.html

您的查询会看起来像这样 (未经测试!)

(let [rules '[[(find-user ?user ?fname ?lname ?email) 
               [?user :user/first-name ?fname]
               [?user :user/last-name ?lname]]
              [(find-user ?user ?fname ?lname ?email) 
               [?user :user/email ?email]]]]

  (:find ?user
         :in $ % ?fname ?lname ?email
         :where 
         (find-user ?user ?fname ?lname ?email)
         conn rules "user" "sample" "user.sample@email.com"))