Fork me on GitHub
#xtdb
<
2023-02-13
>
Namit Shah08:02:48

Suppose I have a document for storing songs,

{
 :song/id 2
 :xt/id :song/2
 :song/name "A Song"
 :song/album :album/12
}
and I have an album document which looks like,
{
 :album/id 12
 :album/name "Dummy Album"
 :album/created-at "2014-09-12"
 :xt/id :album/12
}
Now I want to write a query which gives me the songs with the album attribute getting resolved into the album name. Right now this the query which I wrote,
(xt/q
 (xt/db node)
 '{:find [(pull e [:song/id :song/name {:song/album [:album/name]}])]
   :where [[e :song/id 2]]})
This gives me the :song/album as a map having :album/name attribute. Is it possible to just get the name of the album as the value for the :song/album key? Something like this,
{
 :song/id 2
 :song/name "A Song"
 :song/album "Dummy Album"
}

tatut09:02:12

well one simple way is to (->> …query… (into #{} (map #(update-in [0 :song/album] :album/name)))

1
tatut09:02:30

or you can query without using pull and use :keys to return maps

Martynas Maciulevičius14:02:04

Why is this query not valid?

(xt/q
 (xt/db node)
 '{:find [e]
   :in [[[first-name] 
         [last-name]]]
   :where [[e :name first-name]
           [e :last-name last-name]]}
 [["Petr"]])
I used this example as starting point: https://docs.xtdb.com/language-reference/1.23.0/datalog-queries/#_relation_binding I changed the :in clause to match two different variables.

Michael W14:02:48

You have an extra vector in the :in, and you only gave it a first name of Petr to search for, but no last name.

Michael W14:02:36

(xt/q db '{:find [e]
               :in [[email active?]]
               :where [[e :account/email email]
                       [e :account/active? active?]]}
          ["" true])

Michael W14:02:31

That works against my live database with data.

Martynas Maciulevičius15:02:38

> You have an extra vector in the :in I know I have that extra vector in the :in clause. I want to know how to use this second vector because the syntax of doubly-nested vectors is there:

(xt/q
 (xt/db node)
 '{:find [e]
   :in [[[first-name]]]
   :where [[e :name first-name]
           [e :last-name last-name]]}
 [["Petr"]])
^this works (I didn't test) Basically I want to know why they decided to nest the :in clause not as in your case but as in the most advanced case from here: https://docs.xtdb.com/language-reference/1.23.0/datalog-queries/#_relation_binding

Michael W15:02:51

It's destructuring, you give it a vector of vectors, the :in should reflect the structure of the input.

Michael W15:02:05

The input is [["Petr"]] so you have to tell the :in that you are giving it a vector of vectors.

Martynas Maciulevičius15:02:23

Yes but it says that this query is invalid:

{:find '[(pull result [*])]
       :where [['result :attr 'match-value]]
       :in [[['match-value]
             ['result]]]}
Input:
[[:my-value]]
Output:
"Query didn't match expected structure"
If I try to actually use the second-level vector in the :in binding for different vars then I can type it but I don't really know why I can specify this in a query. And then it says it's also invalid.

Michael W15:02:17

That's a pull query so it works a bit different

Michael W15:02:59

in the pull you are forgoing the :in, and describing what you want in the where.

Martynas Maciulevičius15:02:04

I changed it to non-pull one and it still didn't work. I think you miss something. pull does not do anything here.

Michael W15:02:52

Mmmm, you pasted a pull query and said it was invalid.

Martynas Maciulevičius15:02:25

the pull part is not important. I just copied it from my example and didn't clean it up.

Martynas Maciulevičius15:02:23

The important part is that the :in syntax is not allowed. This is what I ask about. Why do they support different variables in the same :in to run multiple queries on but then don't allow it? I write the validator for this query so I want to find out all cornercases and whether I want to support them.

Michael W15:02:11

So I think it may be partly the quoting, and also pull doesn't use :in afaik because in a pull you are explaining what data to look for, rather than describing the input.

Martynas Maciulevičius15:02:55

Please don't talk about pull:

{:find '[result]
       :where [['result :attr 'match-value]]
       :in [[['match-value]
             ['result]]]}
Input:
[[:my-value]]
Output:
"Query didn't match expected structure"

Michael W16:02:16

(xt/q db '{:find [result]
           :in [[match-value]]
           :where [[result :account/email match-value]]}
          [""])
  => #{[#uuid "UUIDREDACTED"]}

Michael W16:02:33

That works on my database.

Michael W16:02:53

I think it might be your quoting, not an expert though, I had tons of trouble until I just started quoting the entire dictionary.

Martynas Maciulevičius18:02:24

Try this:

(xt/q db '{:find [result]
           :in [[[match-value] [match-value]]]
           :where [[result :account/email match-value]]}
          [[""]])
You didn't understand my question. I already use XTDB for more than a year.

Michael W18:02:27

I guess I don't understand how that would ever be a good query, you specify :in a vector of 2 vectors, but your input is a vector of 1 vector.

Martynas Maciulevičius19:02:52

This is a good query:

(xt/q db '{:find [result]
           :in [[[match-value]]]
           :where [[result :account/email match-value]]}
          [[""]
           ["[email protected]"]])
So I wanted to know what it means if we would have the binding in the :in part. Probably it would be the same as simply running two queries. I wanted to know what I'll deny if I'll not permit to enter this query.

Michael W19:02:33

Ahhh ok yeah I don't know enough about it and did completely misunderstand the question. I do know the destructure you use to bind :in has to match the structure of the input to the query.

refset22:02:24

Hey @U028ART884X I think the ideal error message for this is approx. something like: "a collection of 2x 1-tuples is not a supported binding pattern, did you mean to use a relation binding instead?". Like it's simply not using Clojure's behaviour for destructuring, so you can't assume that anything you could do in (e.g.) a Clojure let binding would work here

refset22:02:16

📣 I'll be running the Virtual Meetup again tomorrow @ 1630 UTC, details are https://discuss.xtdb.com/t/tomorrow-s-virtual-meetup-hands-on-with-history-apis-more/143 - see you there!

👍 1