Dataview date query and date property help

Things I have tried

I’ve tried reading up on the dataview docs and various examples from the github page itself. Also tried searching the subreddit and the github issues as well.

What I’m trying to do

I’m trying to query a list of books I read by a specific year using dataviewjs. I am also trying to make the query more readable by using the year property of the date object which are not able to be accessed. The pages that I have use frontmatter to tag the metadata. For example:

type: “book”
started: 2020-09-06
completed: 2021-05-09

Then I have this query

.where(p => p.completed > 2021 && p.type == "book")

Which works, but if I want to isolate it to a specific year by accessing the year property it does not work like below:

.where(p => p.completed.year == 2021 && p.type == "book")

Which gives this error:

Evaluation Error: TypeError: Cannot read property 'year' of undefined
    at eval (eval at <anonymous> (eval at <anonymous> (app://, <anonymous>:2:25)
    at Array.filter (<anonymous>)
    at Proxy.where (eval at <anonymous> (app://, <anonymous>:9081:39)
    at eval (eval at <anonymous> (eval at <anonymous> (app://, <anonymous>:2:2)
    at DataviewInlineApi.eval (eval at <anonymous> (app://, <anonymous>:12947:16)
    at evalInContext (eval at <anonymous> (app://, <anonymous>:12948:7)
    at eval (eval at <anonymous> (app://, <anonymous>:12959:36)
    at (<anonymous>)
    at eval (eval at <anonymous> (app://, <anonymous>:42:71)
    at new Promise (<anonymous>)

This is strange to me because from the github examples they have this line from a query which seems to access the year property of a returned value from the “time-read” key which seems to be a date. Even if I switch to accessing it by the brackets instead of dot it still doesn’t work, but it seems the dot and bracket access are similar. See the code snippet below:

for (let group of dv.pages("#book").where(p => p["time-read"].year == 2021).groupBy(p => p.genre))

Lastly, I tried a workaround like this also returns nothing:

.where(p => p.completed >= 2021 && p.completed < 2022 && p.type == "book")

So my main questions are:

  1. How should I query it by a specific year instead of after a specific time?
  2. How do I access the year property of a returned value that is presumably date type? Am I not using the correct syntax?

Thank you for the time and reading. I am still new to using this plugin and Obsidian.

I forgot to mention I also tried to access the year property of the implicit field file.mday which works both with equivalancy and comparison operators. This method does not work with the custom field “completed” as I tried above. See the two snippets below that work:

.where(p => p.file.mday.year == 2021 && p.type == "book"))
.where(p => p.file.mday.year >= 2021 && p.file.mday.year < 2022 && p.type == "book"))

So it adds a third question:

  1. An implicit field has the year property, but not a custom field that has yyyy-MM-dd value? Does it not make it a date type object?

Hi jelly, do you have any files with your custom completed field that are blank, or any files that do not have that completed metadata?

I’m thinking somewhere you’re missing that field, so when Dataview tries to run it gets a null error.

1 Like

Hi @nicky2048.

I think that is a good guess I should maybe investigate that some more.

For your first question: no other files have that completed field. I used to have three files for three separate books to test out dataview that had the field and one of them did not have a value as it was not complete. I saw that this was okay according to some query results in the examples return the null in the table. Now I have only one file with a value for completed to try to isolate the issue.

So then for the second part of your question, does that mean that you need to have frontmatter with the custom field for all files? I thought it is supposed to be optional to give you flexibility.


My knowledge in JS is almost “null”. But I have a suggestion: add as previous condition the existence of the field “completed”.
I.e. .where(p => p.completed && p.completed.year == 2021 && p.type == "book")...
When you use p.file.mday.year you don’t have the same problem because file.mday exists always.

1 Like

@mnvwvnm and @nicky2048 your suggestions have greatly helped and provided a working solution. Thank you so much for your help and it is a simple idea in theory, but a nuance I couldn’t overcome without your help.

It seems that dataview can’t handle the the custom date type fields if they haven’t already been instantiated. So @nicky2048’s point about having a completed field in each of the files that you try to query through dv.pages(source) is true. It will solve the problem, but it becomes cumbersome to add all the fields. So @mnvwvnm’s suggestion for adding an additional p.completed && to check for the instantiation or existence of the field would help prevent getting the error of not being able to read the completed.year property.

Thus @mnvwvnm’s explanation about p.file.mday being an implicit field present in all files means that it is declared and initialized with a value so it exists to be able to be read. This shares the same concept as @nicky2048’s suggestion

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