Fork me on GitHub
#datomic
<
2022-03-23
>
Björn Ebbinghaus13:03:22

Can anyone explain why there are differences in the :find specifications for on-prem and cloud? Why doesn't cloud have find-coll [?e ...] or find-scalar ?e . ? Is there something wrong with them? Are they discouraged even for on-prem? Is there a technical explanation?

favila14:03:23

The only one I can think of is maybe too much confusion from people thinking the find-destructure either short-circuits or makes only-one guarantees (it doesn’t do either)

dvingo15:03:06

I just submitted a support request. The Zendesk email replied with: > In order to expedite the resolution of this support request, please provide the information described in this Knowledge Base article: https://cognitect.zendesk.com/entries/96723066-Information-to-provide-with-a-support-request. That link 404s

👍 1
jaret15:03:56

I'll fix that. Sorry!

zendevil.eth15:03:42

I have this query:

(defn sent
  "get user sent threads"
  [user & [{:keys [page]}]]
  (let [page (or page 0)
        db-conn (db/_d)
        to-drop (* messages-per-page page)]
    (->>  (d/q
           '[:find ?e (max ?createdAt)
             :in $ ?user
             :where
             [?e :thread/users ?user]
             [?m :message/thread ?e]
             [?m :ent/created_at ?createdAt]
             (not [?user :user/deleted_thread ?e])
             [?user :user/read ?e]] db-conn
           (:db/id user))
          (sort-by #(inst-ms (last %)))
          reverse
          (drop to-drop)
          (take messages-per-page)
          (map #(db/by-id (first %) db-conn)))))
And it works:
(take 2 (map keys (sent {:db/id 17592186045460} {:page 0})))
;; => ((:ent/created_at :thread/users :thread/subject :user/read) (:ent/created_at :thread/users :thread/subject))
But I also want to get all the :message/thread matches, which will be an array, so I add an ?m in :find
(defn sent
  "get user sent threads"
  [user & [{:keys [page]}]]
  (let [page (or page 0)
        db-conn (db/_d)
        to-drop (* messages-per-page page)]
    (->>  (d/q
           '[:find ?e ?m (max ?createdAt)
             :in $ ?user
             :where
             [?e :thread/users ?user]
             [?m :message/thread ?e]
             [?m :ent/created_at ?createdAt]
             (not [?user :user/deleted_thread ?e])
             [?user :user/read ?e]] db-conn
           (:db/id user))
          (sort-by #(inst-ms (last %)))
          reverse
          (drop to-drop)
          (take messages-per-page)
          (map #(db/by-id (first %) db-conn))))) 
But evaling this still doesn’t show the :message/thread key:
(take 2 (map keys (sent {:db/id 17592186045460} {:page 0})))
;; => ((:ent/created_at :thread/users :thread/subject :user/read) (:ent/created_at :thread/users :thread/subject))
Why is it not shown?

Björn Ebbinghaus15:03:09

In sent you have: :find ?e (max ?createdAt) ?m And then: (sort-by #(inst-ms (last %))) "Last" is an entity id (long)

zendevil.eth15:03:48

@U4VT24ZM3 I updated the question

Björn Ebbinghaus16:03:11

OK... So when you run a query. You get back a set of all matches. There are no "arrays" or "collections" in the query... Instead of: [entity-id [message1 message2 message3] created-at] You get:

[entity-id message1 created-at]
[entity-id message2 created-at]
[entity-id message3 created-at]

Björn Ebbinghaus16:03:20

You can use a pull in your find and pull the messages for a thread:

:find ?e (pull ?e [:message/_thread]) (max ?createdAt)
That would give you something like: [entity-id {:message/_thread [message1 message2 message3]} created-at]

Björn Ebbinghaus16:03:45

But I think it would be better to separate that... 1. Query for Threads 2. sort, filter, whatever them 3. Pull additional stuff like the specific messages later.

zendevil.eth16:03:56

I still get the inst-ms error with:

(defn sent
  "get user sent threads"
  [user & [{:keys [page]}]]
  (let [page (or page 0)
        db-conn (db/_d)
        to-drop (* messages-per-page page)]
    (->>  (d/q
           '[:find ?e (pull ?e [:message/_thread]) (max ?createdAt)
             :in $ ?user
             :where
             [?e :thread/users ?user]
             [?m :message/thread ?e]
             [?m :ent/created_at ?createdAt]
             (not [?user :user/deleted_thread ?e])
             [?user :user/read ?e]] db-conn
           (:db/id user))
          (sort-by #(inst-ms (last %)))
          reverse
          (drop to-drop)
          (take messages-per-page)
          #_(map #(db/by-id (first %) db-conn)))))

Björn Ebbinghaus16:03:28

What is: "the inst-ms error" ? Maybe look into what d/q actually returns?

zendevil.eth16:03:51

I don’t understand this, so this:

(defn sent
  "get user sent threads"
  [user & [{:keys [page]}]]
  (let [page (or page 0)
        db-conn (db/_d)
        to-drop (* messages-per-page page)]
    (->>  (d/q
           '[:find ?e (pull ?e [:message/_thread]) (max ?createdAt)
             :in $ ?user
             :where
             [?e :thread/users ?user]
             [?m :message/thread ?e]
             [?m :ent/created_at ?createdAt]
             (not [?user :user/deleted_thread ?e])
             [?user :user/read ?e]] db-conn
           (:db/id user))))))
returns:
[[#:message{:_thread [#:db{:id 17592186048681} #:db{:id 17592186048686}]} 17592186048679] ...]
But when I remove the pull:
(defn sent
  "get user sent threads"
  [user & [{:keys [page]}]]
  (let [page (or page 0)
        db-conn (db/_d)
        to-drop (* messages-per-page page)]
    (->>  (d/q
           '[:find ?e (max ?createdAt)
             :in $ ?user
             :where
             [?e :thread/users ?user]
             [?m :message/thread ?e]
             [?m :ent/created_at ?createdAt]
             (not [?user :user/deleted_thread ?e])
             [?user :user/read ?e]] db-conn
           (:db/id user))))))
it returns:
[[17592186048679 #inst "2022-03-17T14:18:58.112-00:00"] ...]
Why is it not returning
[[17592186048679 #:message{:_thread [#:db{:id 17592186048681} #:db{:id 17592186048686}]} #inst "2022-03-17T14:18:58.112-00:00"] ...]
as expected in the first case? Is this a bug in datomic?

Björn Ebbinghaus16:03:03

Are you sure you executed the right code? Your first example looks of... Try this:

(defn sent
  "get user sent threads"
  [user & [{:keys [page]}]]
  (let [page (or page 0)
        db-conn (db/_d)
        to-drop (* messages-per-page page)]
    (->>
      (d/q
        '[:find ?e (max ?createdAt)
          :in $ ?user
          :where
          [?e :thread/users ?user]
          (not [?user :user/deleted_thread ?e])
          [?user :user/read ?e]
          [?m :message/thread ?e]
          [?m :ent/created_at ?createdAt]]
        db-conn
        (:db/id user))
      (sort-by second)
      (map first)
      (drop to-drop)
      (take messages-per-page)
      (d/pull-many db-conn ['* {:message/_thread ['*]}]))))

Björn Ebbinghaus16:03:59

Like I said: Try to separate finding the threads from pulling the messages.

jacob.maine18:04:57

@U01F1TM2FD5 IIRC I ran into this long ago. The explanation back then was that there’s a limitation (bug) in Datomic that you can’t reference an entity more than once in a :find expression, or at least in certain situations. The recommendation back then was to convert

:find ?e (pull ?e [:message/_thread]) (max ?createdAt)
into
:find (pull ?e [:db/id :message/_thread]) (max ?createdAt)
That will get you results like this:
[[{:db/id 17592186048679 :message/_thread [#:db{:id 17592186048681} #:db{:id 17592186048686}]} #inst "2022-03-17T14:18:58.112-00:00"] ...]
And you’ll be able to get the entity id out of the first element.