Dv.table for repeated fields

What I’m trying to do

I’d like to have notes containing

`Activity`:: #VideoCall [[ABC]]
`Activity`:: #Work [[DEF]]

be included in a dv.table (see next section).

Things I have tried

```dataviewjs
let pages = dv.pages('"Journal/Activities"')
.where(p => p.Activity.includes("[[ABC]]"));

dv.table(
	["File", "Activity"],
	pages
	.sort(p => p.file.link, 'asc')
	.map(p => [
		p.file.link,
		dv.array(p.Activity)
	])
);
```

This code works fine for notes containing just

`Activity`:: #VideoCall [[ABC]]

but not for notes containing both rows.

Any help would be very much appreciated.

I think the issue in in your where() clause.

When p.Activity contains just one value it’s a string, and so includes() checks to see if “[[ABC]]” is in the string – which it is.

But when p.Activity contains multiple values it’s an array, and so includes() checks to see if any array element matches “[[ABC]]” – which it doesn’t (because it’s “#VideoCall [[ABC]]”).

So your where() clause needs to take into account that p.Activity could be a string or an array. What I usually do in this case is force it to be an array using dv.array() and then go from there.

This where() clause worked for me:

.where(p => p.Activity && dv.array(p.Activity).some(a => a.includes("[[ABC]]")));

Oh, thank you, in particular for your very clear explanation.

Great community here! :blue_heart:

1 Like

Sorry to be here again…

@Craig actually solved my problem, but his code fails when one of the Activity values is, say,

Activity:: [[ABC]]

(This is different from the originally proposed use cases).

And I’m lost again… :frowning:

Hi again @kenNash !

Your new use case adds another possible type for the Activity field, the Link type. A Link is neither a string nor an array, so we have to have additional code to handle this case. Links have properties like path, which is the name of the page.

Here’s what I came up with:

	.where(p => 
		p.Activity && dv.array(p.Activity).some(a => 
	        (a.includes && a.includes("[[ABC]]")) || 
	        (a.path && a.path == "ABC")
	        ));

So now, each time we look at a value for Activity, we’re checking to see if it:

  • is wrapped in an array (we ensure this using dv.array())
  • has the includes method (in which case it’s probably a String)
  • has the path method (in which case it’s probably a Link)

JavaScript isn’t my first language, so likely there’s a more idiomatic way to do this, but it seemed to work in my vault. Here’s what my whole script looks like:

```dataviewjs
let pages = dv.pages('""')
	.where(p => 
		p.Activity && dv.array(p.Activity).some(a => 
	        (a.includes && a.includes("[[ABC]]")) || 
	        (a.path && a.path == "ABC")
	        ));

dv.table(
	["File", "Activity"],
	pages
	.sort(p => p.file.link, 'asc')
	.map(p => [
		p.file.link,
		p.Activity
	])
);
```

Hope this helps!

Craig

I’ve not tested this, but idiomatic it would be cleaner to do typeof a (maybe soelled incorrectly), to check the type and act accordingly. Or whatever equivalent we’ve got to check the property type.

Thank you again @Craig.

This time, your code works for me just as far as “ABC” is a not-yet-created note.
If “ABC.md” does exist, at root level, your code works provided I change
(a.path && a.path == "ABC") into (a.path && a.path == "ABC.md").
If “ABC.md” is not at root level, I must provide its full path.

Am I doing something wrong?

Where can I find a list of all properties of any given type?

:pray:

I’m not proud of this change, but it will detect if the path contains “ABC”, regardless of whether the page exists or not:

	.where(p => 
		p.Activity && dv.array(p.Activity).some(a => 
	        (a.includes && a.includes("[[ABC]]")) || 
	        (a.path && a.path.includes("ABC"))
	        ));

I changed a.path == "ABC"a.path.includes("ABC").

This introduces a side effect: now it will match activity links whose path includes “ABC”, so it might match unintended shorter pages.

Hope this gets you unstuck.

One could also use some variant of “ends with” function to ensure that is the actual noe one is matching against.

Dear @Craig,
I sincerely appreciate your contributions.

Admittedly, your last solution is not ideal… but works for now.

Thank you again.

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