Trying to exclude the null value from the query table

What I’m trying to do

I’ve been writing notes about contact infomation.So I create an Object that includes differents kinds of contact methods as keys in the Frontmatter.

Since there is no promise that everyone has the same contact methods accesible to them,there might be some keys in the Contact object I’ve created.

When I do the Query with Dataview,the keys will show up with a value of null(or any string I set in the Dataview settings.)And that makes the TABLE look messy in the view mode.

So what I’m trying to do is find a way to exclude any key in Object from Frontmatter that holds null value from being shown in the Dataview TABLE.

Things I have tried

I figured that the simplest way to achieve this goal is just deleting the keys if there is no value for it.
But I’m just trying to maintain the structure of Frontmatter for every related note.


Here’s an example of my Frontmatter:

Note: SOMEBODY’S NAME

Name: Somebody
Contact:
{Email: [email protected],
Landline: 123456789, 
Tel: 123456789, 
Web: ,
Skype: ,
Whatsapp: }

And an example of my Query:

Table WITHOUT ID this.Name AS Name,Contact
WHERE file.name = this.file.name


Here’s the images for the example:


Kindly share any solution with me.Many thanks in advance.

My hack with contacts is to use inline fields and to comment out any unnecessary lines for each person.

Expect there are better solutions.

---
Name: Somebody
Contact:
{Email: [email protected],
Landline: 123456789, 
Tel: 567891234, 
Web: ,
Skype: ,
Whatsapp: }
---
> [!INFO]+ `=this.Name`  
>E: `=this.Contact.Email`  
>L: `=this.Contact.Landline`  
>T: `=this.Contact.Tel`  
%%>W: `=this.Contact.Web`  
>S: `=this.Contact.Skype`  
>W: `=this.Contact.WhatsApp`%%  
1 Like

There does not seem to be a good way doing so in dataview because an object cannot be converted to an array.

dataviewjs could be used instead:

~~~dataviewjs
dv.table(
	["name", "contact",],
	dv.pages()
		.where(({ file: { name } }) => name === dv.current().file.name)
		.map(({ name, contact }) => [
			name,
			Object.fromEntries(Object.entries(contact).filter(([, value]) => value)),
		])
)
~~~
1 Like

Brilliant. Thanks for sharing.

There are options within a DQL query also, I think. Some combination of list() and map()/filter() should be able to do this.

Can’t type it out before I’m home from work in some hours, but I do believe it’s feasible.

Whilst thinking about this issue I remembered there is a function nonnull() which picks out values which aren’t null, which led to some simple test-cases:

vararg: `= nonnull(1, 2, null, 4, null, 5)`
contact-fields: `= nonnull(this.contact.Email, this.contact.Landline, this.contact.Web)`

Which returned:
image

So it correctly eliminates the non-null values, but it looses the leading text in the second case, but that can be countered, so try out the following query in your vault, and hopefully see a nice table of your persons with the relevant contact information:

```dataview
TABLE WITHOUT ID
  name,
  nonnull(
    choice( Contact.Email, "Email: " + Contact.Email, null ),
    choice( Contact.Landline, "Landline: " + Contact.Landline, null ),
    choice( Contact.Tel, "Tel: " + Contact.Tel, null ),
    choice( Contact.Web, "Web: " + Contact.Web, null ),
    choice( Contact.Skype, "Skype: " + Contact.Skype, null ),
    choice( Contact.Whatsapp, "Whatsapp: " + Contact.Whatsapp, null )) as Contact
Where Contact
```

This should list the name and only populated fields of Contact for any note having a defined Contact. In my test vault, with only one such note this returns:

image

This query relies on two features:

  • That nonnull() only returns non-null values from the list it receives as parameters
  • Using choice() to test if a given field is non-null, and if so present it in whatever way you feel like (I opted for “Name: value”), or the null value so it’ll be ignored

As you can see, using this method you can choose which fields you want to include by adding/removing lines into the nonnul() parameter list, and you can style/present each field as you feel like it by changing the: "name: " + field part.

It’s a little verbose to do it like this, but it does function, and you’ll most likely only define it once, and then refer to this from any notes where you want to present the information. I would strongly suggest to look into using dv.view() or some other variant to embed this into every person note, so as not to have the actual query typed out in each and every note.

If you include the query directly into the person notes, you’ll get an issue when you sometime in the future decides to add the telegram: field, or whatever field. On the other hand, if the query is imported/embedded, you can change that one place, and everything would just keep on working.

1 Like

Super neat. LIke how it can be reduced to a single column:

---
FirstName: Sammistra
LastName: Bodie
NickName: Sammi
FullName: Sammistra Bodie
Email: [email protected]
Landline:  
Tel: 43356786611111
Web: https://obsidian.md
Skype: 
Whatsapp: 
---

```dataview
TABLE WITHOUT ID
nonnull(
choice( FullName, "**Full Name**: " + FullName, null ),
choice( NickName, "**Nick Name**: " + NickName, null ),
choice( Email, "**Email**: " + Email, null ),
choice( Landline, "**Landline**: " + Landline, null ),
choice( Tel, "**Tel**: " + Tel, null ),
choice( Web, "**Web**: " + Web, null ),
choice( Skype, "**Skype**: " + Skype, null ),
choice( Whatsapp, "**Whatsapp**: " + Whatsapp, null )) 
as Who
WHERE file.name = this.file.name
```

:dancer: :dancing_women: :partying_face::dancing_men::man_dancing: