首页 > 解决方案 > Datomic:“不在集合中”查询不起作用

问题描述

我正在尝试从数据库中获取所有用户,但与一组 UID 相关的用户除外。我已经编写了这个查询,但是当 UID 列表包含多个元素时,由于某种原因,“not”子句不起作用,它会返回所有注册用户。

(d/q '[:find (pull ?e [*])
   :in $ [?uids ...]
    :where [?e :user/id ?uid]
           (not [?e :user/id ?uids])]
 db ["user-uid-1" "user-uid-2" "user-uid-3"])

当 UID 的列表包含单个元素时,查询正常工作(它返回所有用户,除了具有指定 UID 的用户)。

有什么想法可能是错的吗?

标签: databaseclojuredatomic

解决方案


使用[?uids ...]类似SELECT * FROM user WHERE id != uid1 UNION SELECT * FROM user WHERE id != uid2而不是预期的行为SELECT * FROM user WHERE id NOT IN (uids)

例如,在下面的示例查询中,试图获取所有不是苹果或梨的水果

(d/q
  '[:find ?id ?fruit ?fruits
    :in $ [?fruits ...]
    :where
    [?id :fruit ?fruit]
    (not [?id :fruit ?fruits])]
  [[1 :fruit :apple]
   [2 :fruit :orange]
   [3 :fruit :pear]]
  [:apple :pear])
; => #{[3 :pear :apple] [2 :orange :pear] [1 :apple :pear] [2 :orange :apple]}

我们看到查询针对列表中的每个水果运行。:pear[2 :orange :pear] [1 :apple :pear]:apple[3 :pear :apple] [2 :orange :apple]

为了找到不在集合中的所有项目,您需要将集合设置为集合并像这样以标量绑定发送它

(d/q
  '[:find ?id ?fruit ?fruits
    :in $ ?fruits
    :where
    [?id :fruit ?fruit]
    (not [(?fruits ?fruit)])]
  [[1 :fruit :apple]
   [2 :fruit :orange]
   [3 :fruit :pear]]
  #{:apple :pear})
; => #{[2 :orange #{:apple :pear}]}

在您的情况下,您需要像这样重写查询

(d/q '[:find (pull ?e [*])
   :in $ ?uids
    :where [?e :user/id ?uid]
           (not [(?uids ?uid)]
 db #{"user-uid-1" "user-uid-2" "user-uid-3"})

推荐阅读