Found this GEM here https://www.reddit.com/r/ObsidianMD/submit
This code enables you to search for all in body text tagged with #quote. It’s great!
Can anyone help me customise this… I’m so lost when it comes to dataviewjs. 'd like to search according to property fields and list a header and underlying text.
Example:
Class = References
Author = Jane Doe
Title = Janes Book of Fish
Quotes from {{title}}
- Quote number one
- Quote number two
How can I alter the code below to search for Class field, Author field, Title field and then list the quotes I have listed in desperate reference notes?
I might have five references where Jane Doe is an author (or co-author). I want to list the quotes from each title in a single note that’s probably titled [[Jane Doe Quotes]]. The code will produce the following:
Quotes from Janes Book of Fish
- Quote number one
- Quote number two
Quotes from Janes Doe Memoir
- Quote number one
- Quote number two
- Quote number three
Quotes from The Mysterious Deaths of Jane and John Doe
- Quote number one
- Quote number two
If you’re able to provide some help that would be so greatly appreciated!
Thanks and stay classy Santiago
const pagesWithQuotes = await Promise.all(
dv.pages("#quote").map(
({ file }) =>
new Promise(async (resolve, reject) => {
const content = await dv.io.load(file.path);
resolve({
file,
content,
});
})
)
);
// Create an array of quote objects, each containing:
// {
// quote: string, // the quote text itself
// file: File, // a reference to the file containing the quote
// maybeBlockId: string, // the block ID at the end of the quote, if it exists
// maybeNearestParentHeading: string // the nearest parent heading, if it exists
// }
const quotes = pagesWithQuotes
.map(({ file, content }) => ({
file,
quotes: content
// Split into lines
.split("\n")
// Remove any bullets or preceding whitespace. Separate
// out quote and the block ID, if a block ID exists.
.map(
(content) =>
/\s*(\s|\*|\-)*\s*(?<quote>.*?)\s*?(?<maybeBlockId>\^[0-9a-zA-Z\-]{0,15})?$/gm.exec(
content
)?.groups || {}
)
// Find the nearest previous heading, if one exists
.map(({ quote, maybeBlockId }, lineNumberZeroIndexed) => ({
quote,
maybeBlockId,
maybeNearestParentHeading: /\n#{1,6}\s(.*)/gm
.exec(content.split("\n").slice(0, lineNumberZeroIndexed).join("\n"))
?.last(),
}))
// Only return lines with the "#quote" tag in them
.filter(({ quote }) => quote.includes("#quote"))
// Remove the "#quote" tag from each quote string
.map(({ quote, maybeBlockId, maybeNearestParentHeading }) => ({
quote: quote.replace("#quote", "").trim(),
maybeBlockId,
maybeNearestParentHeading,
}))
// Filter out empty values (this would happen
// if a line contained only the text "#quote")
.filter(({ quote }) => Boolean(quote)),
}))
.reduce((accumulator, { file, quotes }) => {
quotes.forEach(({ quote, maybeBlockId, maybeNearestParentHeading }) =>
accumulator.push({ quote, file, maybeBlockId, maybeNearestParentHeading })
);
return accumulator;
}, []);
const getLinkForQuote = ({ file, maybeBlockId, maybeNearestParentHeading }) => {
if (maybeBlockId) {
// Block ID exists. Return a link to the block ID.`[[${file.path}#${maybeBlockId}|${file.name}]]`);
return `[[${file.path}#${maybeBlockId}|${file.name}]]`;
} else if (maybeNearestParentHeading) {
// A parent heading exists. Return a link to the heading.
return `[[${file.path}#${maybeNearestParentHeading}|${file.name}]]`;
} else {
// Fallback to linking to the page
return String(file.link);
}
};
quotes.forEach(({ quote, file, maybeBlockId, maybeNearestParentHeading }) => {
dv.paragraph(
`${quote} (${getLinkForQuote({
file,
maybeBlockId,
maybeNearestParentHeading,
})})`
);
});