How to get the first element, second etc of a tuple?

I have a simple query that should output 96 (as I have a block with that id):

#+BEGIN_QUERY
{:title "Blocks"
 :query [
        :find ?b ?name
        :where
        [?b :block/name ?name]
        [(= ?b 96)]
 ]
:view (fn [info] [:div (for [arg info] (first arg))])
}
#+END_QUERY

but it fails with a render error: “96 is not ISeqable”.

  1. What is the problem here?
  2. Is there a way to just destruct a tuple like in JS for example ([id, name]) => ...?
  1. 96 is a single value, not a sequence of values.
  2. Some options to consider:
    • [:div (first info)]
    • [:div (for [[id, name] (partition 2 info)] id)]
1 Like
  1. I know it’s a single value, but why? I pass a tuple of [96 "some name"]

  2. So this works, thanks:

#+BEGIN_QUERY
{:title "Blocks"
 :query [
        :find ?b ?name
        :where
        [?b :block/name ?name]
        [(= ?b 96)]
 ]
:view (fn [info] [:div (for [[id, name] (partition 2 info)] id)])
}
#+END_QUERY

I still don’t understand why (for [arg info] (first arg)) doesn’t.

for iterates what you pass, so first is given 96 alone

What do you mean? for [arg data] ... - data is a collection, arg is an item, no?

Try (for [arg info] (str arg ",")) to see the items of the collection.

I get:

96,js,

for a tag #js with id 96.

So if we have data like:

[
  [1, 'a']
  [2, 'b']
  [3, 'c']
  ...
]

and pass it to for in (for [arg info] arg), it will iterate:

1
'a'
2
'b'
3
'c'

instead of:

  [1, 'a']
  [2, 'b']
  [3, 'c']

But it doesn’t make much sense. What is going on here? Why did it flatten the structure by itself?

It is not flattened by for, it is produced flat by the query. If you want a proper structure, should use :keys

Sorry, why do you say it’s flat? It’s a sequence of sequences:

[
  [1, 'a']
  [2, 'b']
  [3, 'c']
]

So it’s a type as in [number, string][] speaking in TypeScript, which is an array of tuples.

The anonymous function here:

:view (fn [info] ...)

receives a parameter of that type, correct? I.e. the array of tuples.

Now when we pass it to for:

:view (fn [info] (for [x items]) ... ) 

it should make x to iterate through the tuples:

[1, 'a'], [2, 'b'], ...

but instead it iterates:

1 "a" 2 "b" ...

Why is that?

Clojurescript in :view takes over Datalog’s output, and Datalog outputs its own thing, it doesn’t try to satisfy our assumptions. I cannot answer beyond that.

There’s an assumption that the :find outputs a tuple. But this is not what happens.
I cannot speak to why this doesn’t happen, but that has probably to do with the implementation Logseq uses.
So instead you just get a list of values for your result.
Consider my test:

#+BEGIN_QUERY
{:title "Blocks"
 :query [
        :find ?b ?name
        :where
        [?b :block/name ?name]
        [(>= ?b 2395)]
 ]
}
#+END_QUERY

Notice that there are 6 results! Not 3.

We can use pull to get a “better” result…

#+BEGIN_QUERY
{:title "Blocks"
 :query [
        :find (pull ?b [:db/id :block/name])
        :where
        [?b :block/name ?name]
        [(= ?b 2395)]
 ]
 :view (fn [info] [:div (for [arg info] (second arg))])
}
#+END_QUERY

(don’t ask why it is suddenly the second argument… idk…)

To see what happened, we can use:

#+BEGIN_QUERY
{:title "Blocks"
 :query [
        :find (pull ?b [:db/id :block/name])
        :where
        [?b :block/name ?name]
        [(>= ?b 2395)]
 ]
 :view (fn [r] [:pre.code (pprint r)])
}
#+END_QUERY


Now there are actually 3 results. Same can be achieved with :keys as mentioned by @mentaloid .

That just leaves me with the question of… why?
Why would you want to retrieve this information in the first place? It shouldn’t be something users are otherwise concerned with.

1 Like

Because:

  • I need to be able to ask questions to the database and get answers
    • As the database schema provided doesn’t tell me almost anything
      • Because it’s very brief
      • Because I’m not a Clojure geek to see through

So I need to start with something. I don’t feel comfortable with monkey-editing requests I don’t understand scattered here and there. I’m still trying to find a ground to start with.

Thanks to your help folks, this process is evolving. Otherwise I would have dropped it, because honestly - it looks like a geek tool for Clojure geeks.

I really hope I will come up with a working system soon and before I give up :pray:

1 Like

Now I see! Well, I was getting the same results but I thought that the reason was the view-function used by default. But now I understand it’s how results provided by :find. Thanks!

And as for keys, I see now the reason as well. Cool.

1 Like
  • We don’t ask the database, we ask the graph stored in it.
    • The database is an implementation detail.
  • A brief schema is a blessing, as it doesn’t get in the way.
    • What matters is the custom schema built with Logseq’s properties.
  • Nobody in this thread so far is anywhere close to a Clojure geek.
    • We use it only in Logseq and only when necessary.
  • We answered some of your questions just because you made them.
    • They are not relevant to most users’ actual needs.
1 Like

That would be the case if you could communicate with the graph in natural language. Otherwise - you have to deal with “an implementation detail”.

That’s true. Once you learned it :slight_smile:

I love your confidence in knowing what others need :wink:

I don’t need to know their needs, I just know that:

  • they have no idea of their needs before they acquire enough experience
    • In other words, I am confident that they primarily need experience.
  • they don’t need to understand the details
    • As a matter of fact, most users cover their needs with less than half of your current understanding.
      • For example, most users don’t understand :view
      • With or without monkey-editing, they successfully cover their needs.

You have to deal with the implementation, but not with its details.

1 Like

Can’t agree more. Judging from my 20+ years of notes taking experience!

Many thanks for you help @mentaloid! I really appreciate it :+1: