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"))
我目前正在将我的 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"))