Compose multiple mdFiles to one for query in dataviewjs

Things I have tried

Hello,

I want to do some kind of “Lego” the DQL for a query in multiple md.Files.

File 1:

upper part of the finally composed File

TABLE fieldA, fieldB, field67
FROM "folder"
WHERE things = "1"
...

FIle 2:

lower part

WHERE color = "red" AND type  = "2"

What I’m trying to do

So, that I call like this:

$=dv.span(await dv.io.load("File_upper.md" + "File_lower.md"))

Is this possible at all, to link multiple files?
as if it were only a text string…?
In this way, one could split up longer queries that often have the same content, but only differ in 1 or 2 things, and not have to touch everything twice.

thanks

the upper part of the query contents a long choice function, (which select diverse icons) and where the file is determined (this.file.link), that occurs in many files, and it’s actually static and the same.
The lower part is the important part, which depends on the special use case, one special WHERE clause.
My idea now was to outsource this upper part and to have it only once, so to speak, which would simplify a possible update.

Well I tried the following:
I set the upper part in a File upperFile.md

and lower part in a File lowerFile.md

then I tried to set them in a variable
and combine them

let upFileStr = await dv.io.load("upperFile.md");
let downFileStr = await dv.io.load("lowerFile.md");
let allFileStr = upFileStr + lowerFileStr;
dv.query(allFileStr);

Well, I am already aware that this is not the entirely correct code
but it should only show my thoughts.
But I have no clue, how to combine this 2 files so that I can use them as a query.

Hello,

I tried another one.

async function main() {   
const data = await dv.span([     
dv.io.load("path/file_upper_part.md"),     
dv.io.load("path/file_lower_part.md"),   
]);    
const results = await dv.execute(data);   
console.log(results); }

but there is no output.
The console says:

Uncaught TypeError: Cannot read properties of null (reading 'querySelector')
    at eval (plugin:obsidian-icon-folder:3720:39)
    at t.e.tryTrigger (app.js:1:1045441)
    at t.e.trigger (app.js:1:1045374)
    at t.trigger (app.js:1:1812575)
    at t.onPaneMenu (app.js:1:1364251)
    at t.onPaneMenu (app.js:1:1485400)
    at t.onMoreOptions (app.js:1:1355632)
    at app.js:1:1353437
    at HTMLAnchorElement.<anonymous> (app.js:1:1355377)

It can’t be that difficult, where am I going wrong?

There are some caveats to this approach which has stopped you from getting it to run properly, so let us go through them one by one.

Joining the query parts

Working out of this example to get the different parts:

let upFileStr = await dv.io.load("upperFile.md");
let downFileStr = await dv.io.load("lowerFile.md");
let allFileStr = upFileStr + lowerFileStr;

When you join the two parts of the query, it’s not unlikely that you join them without any white space between them, and you get something like: ...WHERE things="1"WHERE color ....

To fix this, either use upFileStr + "\n" + lowerFileStr, or be very sure that there is an extra return in the upper part file. Also be sure that there is no extra text or frontmatter in either file. This will be included in the joined text string.

A query needs to be awaited

You need to do await dv.query() to allow the query to be executed properly. There is a variant dv.tryQuery() which will fail miserably when wrong, which doesn’t need await, but I find it better to use the first variant. (This is a matter of personal preference, though)

When you await such a query, you get a structured return, so if you do console.log(dv.query( ... )) you’ll see something like this:

image

This shows us that we don’t actually get the finalised query, but we get an indicator to whether it went well or not in the successful variable, and the actual result in the value variable.

This comes in handy when we want to produce the final result.

Presenting the structured result

A dv.query() needs to be done in combination with either dv.taskList(), dv.list() or dv.table(), see Codeblock Reference - Dataview. And these require slightly different way of handling the result from the dv.query().

In your case you’re doing a TABLE query, it seems, so you need to do something along these lines:

const result = await dv.query( ... )
if (result.successful)
  dv.table(["Field A", "Field B", "Thing"], result.value.values)
else
  dv.paragraph("~~~~\n" + result.error + "\n~~~~")

Here we first await the query, and store the result in result, then we check if it was a successful run, and present the output through dv.table(). Finally, if it failed we present the error message.


Fully working example of combining query parts with base data

To be able to test this I produce the following files, and test data:

upperPart.md

TABLE WITHOUT ID fieldA, fieldB, thing
FLATTEN things as thing
WHERE this.file.name = file.name

lowerPart.md

WHERE thing = 2

Combining the script parts

fieldA:: aValue
fieldB:: bValue
things:: 1, 2, 3, 4

```dataviewjs
const upperPart = await dv.io.load(dv.current().file.folder + "/upperPart.md")
const lowerPart = await dv.io.load(dv.current().file.folder + "/lowerPart.md")

// console.log(upperPart, lowerPart)
const result = await dv.query(upperPart + lowerPart)
// console.log(result)
if (result.successful)
  dv.table(["Field A", "Field B", "Thing"], result.value.values)
else
  dv.paragraph("~~~~\n" + result.error + "\n~~~~")
```

In the example above I’ve compiled my own test suite to properly test this, and hopefully the text and the example will help you achieve your goal, and understand why your previous attempts have failed.

1 Like

Thank you very much for your reply and your efforts.

That it is so complicated after all… :flushed:
I don’t think I’m getting anywhere with the whole enumeration of the fields, because the upper query is more complicated, because of multiple choice functions.
(maybe I could send you a test-vault, but this could shock you :wink:)

Both files (upper & lower) are pure dataview, no yaml frontmatter, no other frontmatter.

I thought, i could “melt” the two files in a js-function like that

File: getAllQuery.js

async function getAllQuery() {
	let uppPart = await dv.span(dv.io.load("upperPart.md");
    let lowPart = await dv.span(dv.io.load("lowerPart.md");
  
	let allParts = uppPart + lowPart ;
	
	return allParts
}
module.exports = getAllQuery

Then the complete query should be contain in getAllQuery

Now you would only have to use this function and include it in a query command.

in templater the command goes:

const allQuery = await tp.user.getAllQuery(tp);

but how to get that in dataviewjs?

Please read my reply, and do as it says. It’s not really that complicated. Your end script will look very similar to be example script.

1 Like

It turns out the headers are somewhat more complicated in his case, and I’ve mostly used my own redefined headers when doing queries like these. However there is a neat solution, as the result object does return the headers from the query, as well.

So to preserve the headers from the query, one should do:

dv.table(result.value.headers, result.value.values)

It just struck me that you might not be watching the console.log() output in Developers Tool in the Console pane? Are you only seeing the result in the editor window in either live preview or reading view?

If that’s the case, it explains a lot, as you then might have the first part of reading the file all wrong, which I’ve assumed has been right all along.

Please do the following query in the same folder as the original query is supposed to be. You can even do it in front or after the other query.

```dataviewjs
const curr = await dv.io.load(dv.current().file.folder + "/dv_incl_ProjDatei_zutunUntTeil.md")

const curr_no = await dv.io.load(dv.current().file.folder +
"/dv_incl_ProjDatei_zutunUntTeil")

const full = await dv.io.load("Museum/Projekte/dv_incl_ProjDatei_zutunUntTeil.md")

const full_no = await dv.io.load("Museum/Projekte/dv_incl_ProjDatei_zutunUntTeil")

const sub = await dv.io.load(dv.current().file.folder + "/Museum/Projekte/dv_incl_ProjDatei_zutunUntTeil.md")

const sub_no = await dv.io.load("Museum/Projekte/dv_incl_ProjDatei_zutunUntTeil")

dv.paragraph(`Just current dir: ${dv.current().file.folder}`)
dv.paragraph(`current dir, with extension: ${curr}`)
dv.paragraph(`current dir, without extension: ${curr_no}`)

dv.paragraph(`full dir, with extension: ${full}`)
dv.paragraph(`full dir, without extension: ${full_no}`)

dv.paragraph(`full dir, with extension: ${sub}`)
dv.paragraph(`full dir, without extension: ${sub_no}`)
```

Execute this script, and report back what you get. Hopefully either one (or possibly two) of these should include the lower part of your query, and we need to know which one.

1 Like

in Live preview as well in reading mode occurs the error.
here the output of your last query:

Just current dir: Museum/Projekte
current dir, with extension: AND kapitel = "Weinert"
current dir, without extension: undefined
full dir, with extension: AND kapitel = "Weinert"
full dir, without extension: undefined
full dir, with extension: undefined
full dir, without extension: undefined

edit: so i changed the code:

const upperPart = await dv.io.load(dv.current().file.folder +
"/dv_incl_ProjDatei_zutunObTeil.md")
const lowerPart = await dv.io.load(dv.current().file.folder +
"/dv_incl_ProjDatei_zutunUntTeil")

and this came:


but there should be 5 records, like this

grafik

of course this has to be the right code:

const upperPart = await dv.io.load(dv.current().file.folder + "/dv_incl_ProjDatei_zutunObTeil.md")
const lowerPart = await dv.io.load(dv.current().file.folder + "/dv_incl_ProjDatei_zutunUntTeil.md")

and I had to set an return in the last line of the upper part, because the AND was to close to the parameter

and now… all 5 records are shown.
fine! :smiling_face_with_three_hearts:

ok, what do I owe you? :wink:
once again you saved me…

many thanks, and have nice Sunday!

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.