Datomic - 使用 OR 子句

Datomic - working with OR clause

我目前正在将我的 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 文档),因为 or 子句中使用的所有子句必须使用同一组变量。如何围绕不同的变量集设置 OR 子句?

您的查询应该有效。您的所有子句 do 使用相同的变量:?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]}

这与这个问题非常相似:

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"))