How to flatten and remove duplicates in query results?

Using the following query I get a list of arrays. I want to flatten these arrays into one array and remove duplicates. Not sure what built in functions are available.

${query[[
  from index.tag "page"
  where name:startsWith("Journal/")
  select {
    Tags = _.tags
  }
]]}

Here is my best failed attempt

${query[[
  from index.tag "page"
  where name:startsWith("Journal/")
  select {
    Tags = utils.unique(utils.flatten(_.tags))
  }
]]}

-- Flattens a list of lists into a single list
function utils.flatten(list_of_lists)
  local flat = {}
  for _, sublist in ipairs(list_of_lists) do
    for _, value in ipairs(sublist) do
      table.insert(flat, value)
    end
  end
  return flat
end

-- Removes duplicates from a list while preserving order
function utils.unique(list)
  local seen = {}
  local result = {}
  for _, value in ipairs(list) do
    if not seen[value] then
      seen[value] = true
      table.insert(result, value)
    end
  end
  return result
end

In general, I would like to know how to flatten arrays in lua too.

But for a specific usecase similar to yours, I’m using a workaround:

${query[[
  from index.tag "tag" 
 where _.parent == "page" and page:startsWith("Journal/")
]]}

Thanks, that worked! This is what I ended up with.

${query[[
  from index.tag "tag"
  where _.parent == "page" and page:startsWith("Journal/") 
  select  "[[" .. _.name .. "]]"
]]}

Does silverbullet have any documentation about the object model?

This obviously depends on how you use tags in your instance, but format "[[" .. _.name .. "]]" for tags looks a bit odd to me.

In my instance I have a list of tags that are attached to tasks shown like this:

${template.each(query[[
select {name=_.name}
  from index.tag "tag" 
 where _.parent == "task"
]], template.new[==[#${name} ]==])}

It ensures that tags are rendered as a tag (with all your custom styling still in place), and link to virtual page also is there.

That’t better than what I did, thanks