Unique values for key in dataviewjs

I am new to to javascript and trying to get a list of unique/distinct values for a specified key/property in dataviewjs. I am trying to use “a javascript function returning an array of string” for a query to create a field in MetaData Menu.

I have this working in DQL but can’t manage to get it translated to dataviewjs…

For this example, I would like all of the unique genres of books; both genre and class are specified by a “class” key/property. Let’s say I have 3 books: 2 comedy and 1 horror. So my resulting list should be length 2 with comedy and horror.

Here is the YAML from a sample note:

---
class: book
genre: comedy
---

In DQL, this works:

LIST
WHERE class = "book"
FLATTEN genre
GROUP BY genre

In dataviewjs, it does not work and I get each appearance of each genre, i.e., comedy, comedy, horror.

dv.pages().where(p => p.class == "book").map(p => p.genre)

Many thanks for your help!

Does this work for you?

~~~dataviewjs
let propertyName = "your property name here" 

let uniqueProperties = [];

Object.values(app.metadataCache.getAllPropertyInfos()).filter((prop) => {return prop.name === propertyName}).forEach(async (prop) => {
    const propAndValues = prop;
    propAndValues.values = DataviewAPI.func.unique(
        DataviewAPI.pages("")
            .filter((page) => page.file?.frontmatter?.[propAndValues.name])
            ?.[propAndValues.name]?.array?.(),
    );
    uniqueProperties.push(propAndValues);
});

uniqueProperties = DataviewAPI.func.unique(uniqueProperties);

dv.table(
    ["Property name", "Type", "Unique values"],
    uniqueProperties
        .sort((a, b) =>
            a.name.localeCompare(b.name, "en", { sensitivity: "base" }),
        )
        .map((prop) => [prop.name, prop.type, prop.values.sort()]),
);
~~~

I use this to get a list of distinct value of a list type, here for the tags but it work for any other list field:

dv.pages().groupBy(p => p.tags).key.distinct()

So you can use :

dv.pages().where(p => p.class == "book").groupBy(p => p.genre).key.distinct()
1 Like

I agree with @Anwen on using groupBy() to gather up the unique values, but if I’m not mistaken you’re not required to do the .key.distinct in your case. You could present the result of that directly into a list, something like:

´$= dv.list( dv.pages().where( p => p.class == "book" ).groupBy(p => p.genre) )`

The difference would be that this query doesn’t trim down the result into single entries, but keeps the list of pages gathered into the rows object. Using the key.distinct one strips down the data set. Either case can be very useful depending on circumstances, so I just wanted to point out this difference which both uses the same base technique to single out the unique genre values in your query.

1 Like

Indeed, but to use with metadata menu, it is necessary to take just the unique entries for it to work. What you explain can be useful for other functionalities but not for metadata menu.

2 Likes

I truly stand corrected, as I missed that part of the request that it was to be used in the MetaData Menu. I think I’ll still leave my response as is, just to illustrate the difference of the approaches depending on contexts!

1 Like

Thank you. I tried the approaches suggested by @Anwen and @holroy, and indeed for MetaDate Menu, @Anwen’s approach is the solution.

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