Help: #howto Build Recipe "database" in Obsidian (complex)

Build Recipe “database” in Obsidian


*I usually write in Dutch, but for the sake of being able to ask help on the Obsidian Forum, this one’s in English. I will translate it into Dutch to keep in my vault under “Culinair”, once I know how to set this up according to my wishes. #remindertoself *


Why I want to build this “database” of interlinked recipe and ingredient notes

I have thousands of PDF Recipe books and also thousands of TXT recipes and lots of them in a recipe manager called Paprika.

I am a diabetic and need to eat #LowCarb. I plan to go over all my collected recipes and pick the recipes that are precisely that. And which are to my taste, of course.

Paprika is excellent, but having my recipes in Obsidian would give me the benefit of interlinking stuff. Also, I want my children and grandchildren to be able to access my recipes without any specific program, once I am no longer roaming the earth.

What I would like this “database” to be able to do for me

  • I want every main ingredient/category/health benefit (and maybe other stuff in the future) to have its own note and link to that note from within a recipe note.

  • I want that, because I maintain other resources that have to do with diabetes/losing weight/health/excercise/etc and I want to gain insight on how this all could come together as some sort of “life advice” per health complaint/goal. I think I can achieve that using Obsidian.

  • The ingredient note will contain important info about the ingredient. Some of them are;

    • what category (meat, veg, herb, dairy, plantbased etc) (link to category note(s))
    • health benefits (link to health benefits note(s))
    • what’s the glycemic load
    • how many carbs/fiber/fat/protein/vits/minerals etc
    • other specific information about the ingredient I find valuable
  • I want to automatically insert the name (as a link) of every recipe that uses this ingredient and that links to the ingredient note, right below the above main info on the ingredient note. #important!

  • I want to automatically insert the name (as a link) of every recipe that falls under one or more categories and that links to this/those category/categories note(s), right below the above main info on the category note(s). #important!

  • I want to automatically insert the name (as a link) of every recipe that falls under one or more health benefits and that links to this/those health benefit note(s), right below the above main info on the health benefit note(s). #important!

  • I have been thinking about usings tags instead of separate notes. Not sure what the (dis)advantage of doing so would be.

What kind of structure would you advise me, to achieve the above?
Anyone other ideas to achieve the “life advice” concept ?

11 Likes

Without thinking too much about it, I’d probably go for a combination of YAML, tags and DataviewJS (because it’s more flexible than pure Dataview and you could calculate nGL from the grams of an ingredient used in the recipe, maybe even divided by numer of portions).

So probably, for ingredients, something like this:

---
ingredient: watermelon
category: fruit
GI: 72
GL: 4  # per 100g
tags: [ingredient, fruit]
---

… description, notes …

### Used in these recipes

… some dataviewjs …

For recipes, something like this:

---
recipe: melon salad
category: dessert
serving: 100 g # blank-separated, so "unit" can be split
portions: 4
ingredients:
  - [watermelon, 80 g]
  - [sugar, 20 g]
tags: [recipe, dessert]
---

… some dataviewjs to show the ingredients …

… some dataviewjs to calculate totals from the ingredients, maybe combined GL, Insulin Index, or the like …

… preparation …

… notes …

Then maybe lists of recipes, categories, ingredients in separate notes, finding and summarizing all wanted information using DataviewJS.

Something like that. As I said, without thinking too much. All values are pure fake, except GI & GL of the watermelons.

Warning: This might turn out quite a job, especially all the DataviewJS stuff, and unit conversions (how many tbsp has a pitcher?, hee hee, Hint: 1 tbsp in Australia: 20 ml, in U.S., U.K. and most of Europe 15 ml).

3 Likes

Thank you for thinking along! I have found Text Expand (not Text ExpandER!) to help me with listing all the recipes a given ingredient/category/health benefit etc is mentioned in. That’s already a start. Dataview is something I will seriously need to study, but it may (probably will) have advantages I cannot yet see clearly the use for. Yet.

As to conversion of measurements like cup, tb, tbs etc: I know where most of my recipes come from (as in country of origin/creator) and there are many very good conversion websites. I admit, it will be some fair amount of work to put it in for the majority of commonly used ingredients in #LowCarb meals, but once it’s in for an ingredient, it’s in. For all the other recipes to use.

There’s no real deadline yet for this, I am building it primarily for myself and my family and friends. But, who knows…Once it’s done (if ever haha) I might just give it away for people to use.

@Moonbase59 Matthias, could you explain to me in simple laymens’ terms, what the purpose and/or advantage is, of putting stuff in YAML?

I think I am somehow missing the whole point of information specifically put in YAML. But I would really like to know, so I can decide if I am going to use it or not.

Thanks again!

Hey Fieke,

why YAML? Hmm, maybe because I’m an overly organized techie, hee hee. Let me think why I love using YAML:

  • It’s separate from my note content, so ideal for “meta” info.
  • It does neither interfere with Markdown nor display (well, except if you want it to).
  • I’m used to it, working with Pandoc and LaTeX for years.
  • The variables used in YAML can easily be parsed and used in, say, Dataview.
  • I could, if I wished, modify before displaying. Just imagine you have ingredients for a recipe stored per serving, plus you have a “portions” YAML variable. You could then adjust “portions” from 4 to 12 if holding a big party, and the note text could automatically calculate the needed amounts!
  • Guess that last one is the main reason why I generally love parametrized stuff. And with Obsidian, that’s YAML. :wink:

Let’s make a simple example. I have my above YAML, and want to display portions and serving in a note, without ever bothering about having to also change the note text when changing the YAML:

I’d write

**Portions:** `this.portions` (of `this.serving` ea.)

somewhere in my note and get:

Portions: 4 (of 100 g ea.)

in my note when previewing or printing it out. Nice, eh? And besides, I’m not forced to use Dataview for this, I could instead use Templater, for instance. Just because they are just variables that are accessible.

Maybe I overdo it, but I just love stuff like this. :slight_smile:

3 Likes

Here’s another one, just jotted down two notes for explaining:

This is the “Meldon Salad” note:

---
recipe: Melon Salad
category: dessert
serving: 100 g # blank-separated, so "unit" can be split
portions: 4
ingredients:
  - [watermelon, 80 g]
  - [sugar, 20 g]
tags: [recipe, dessert]
---

# `=this.recipe`
… some dataviewjs to show the ingredients …

… some dataviewjs to calculate totals from the ingredients, maybe combined GL, Insulin Index, or the like …

… preparation …

… notes …

and this a simple “Dessert List”:

# Desserts

```dataview
list
where recipe and category="dessert"
```

Try them and you’ll see why I like YAML. And Obsidian.

2 Likes

<sitting with a grin on my face after reading your reply, I like people with passion for [whatever]>

Thanks for explaining! It makes a lot more sense now.

And for the record, I think it is by no means “overly” organized when you think like you do. For an ADHD mind like mine, nothing can be too over-organized, as long as it is simple to set up and maintain. And I am prepared to study stuff, if that means I can achieve exactly that. I keep notes in Obsidian about why and how I manage to make things work and where I picked that workflow up. If I don’t, I will forget and need to start from scratch, each time I need to do the same. My CSS files are also /* overly commented */ :wink:

=> I think I need to dive into Dataview.

Is it okay to ask you for more help, if need be?

I might need quite a bit of it in the beginning, but I am a fast learner, though I am an absolute alpha-person - give me languages and words and I can speak and write and do magic with words. But for a woman, I think I am quite a computer nerd, knowing way more about digital stuff than most of my female peers. At least that is how my family and friends see me :slight_smile:

PS I am obsessed with Obsidian, too ! Now I need to fall in love with YAML and Dataview :stuck_out_tongue:

3 Likes

I am definetely going to try your examples out!

I am glad I have not yet “obsidianized” my recipes, just some of them. I can still easily adapt those and the template.

I will let you know how things turn out :slight_smile:

Also laughing here … I’d immediately start flirting if you weren’t in a relationship. :rofl:

Asking questions? Yeah, sure, if I have time and can answer them. Although I’m currently quite obsessed with @valentine.195’s Obsidian Leaflet maps.

Just keep in mind all this was just jotted down off the top of my head, without thinking too deeply about it. You might come up with a much better structure. (Because you want it.)

I guess with some structuring and a nice set of templates, this could go a long way!

Veel plezier met experimenteren!

2 Likes

Grinzzz…flirt away, I am not in a relationship, I am a (double) widow. My guys are in heaven. Just saying :stuck_out_tongue: :smiley:

Oh boy…now you have made me want to know about what Obsidian Leaflets are. Sigh. <side-tracked…okay for now>

2 Likes

Made my day … imagine the largest grin ever. :grin: :nerd_face:

Guess I have to get interested in … a-hem … recipes more now …

I now fear the moderators will take all my badges away and ban me for constantly getting off topic …

3 Likes

Well, I think both of us are having a good day hahaha. Thank you, Obsidian :joy:

If the moderators would dare!!! They should be proud of their first openly admitted flirt on their forums :stuck_out_tongue: :joy:

Hee, hee. And here, because I couldn’t keep my fingers from it, another version of the melon salad, showing an ingredients list auto-generated from the YAML (try modifying, adding ingredients, changing # of portions, etc.):

---
recipe: Melon Salad
category: dessert
serving: 100 g # blank-separated, so "unit" can be split
portions: 4
ingredients:
  - [watermelon, 80 g]
  - [sugar, 20 g]
tags: [recipe, dessert]
---

# `=this.recipe`

## Ingredients for `=this.portions` portions (`=this.serving` ea.)

```dataviewjs
var i;
for (i=0; i < dv.current().ingredients.length; i++) {
    var name = dv.current().ingredients[i][0];
    var amount = dv.current().ingredients[i][1].split(" ")[0];
    var unit = dv.current().ingredients[i][1].split(" ")[1];
    var link = '[[' + name + ']]'
    dv.paragraph("- " + amount * dv.current().portions + " " + unit + " " + link);
}
```

… some dataviewjs to calculate totals from the ingredients, maybe combined GL, Insulin Index, or the like …

… preparation …

… notes …

The only current drawback is that after changing the YAML, you need to close & reopen the note, so Dataview knows to update its cache.

I know there is a plugin called Buttons. I have no clue how that works yet, but I presume one could create a button that closes and re-opens the note by clicking it.

I think I can understand Dataview, but I am by no means skilled in javascript or DataviewJS. If Javascript were a normal language using words instead of numbers, it would make things a whole lot easier for me. But since it’s not, I will have to rely on Dataview OR people like you :blush: at least for now.

For the ingredients, a “used in these recipes” could look like this:

---
ingredient: watermelon
category: fruit
GI: 72
GL: 4  # per 100g
tags: [ingredient, fruit]
---

# `=this.ingredient`
… description, notes …

### Used in these recipes

```dataviewjs
dv.list(dv.pages()
    .where(p => p.recipe && p.ingredients.map(e => e[0])
        .indexOf(dv.current().ingredient) >= 0)
    .file.link
);
```

Now if that isn’t a reason to start loving YAML and Dataview

1 Like

Just for the fun of it, here are two more:

Recipes TOC

---
tags: [recipe, toc]
---

# Recipes TOC

## Drinks

```dataview
list
from #drink or #drinks
where recipe
```

## Food

```dataview
list
from #food
where recipe
```

Ingredients by category TOC

---
tags: [ingredient, toc]
---

# Ingredients by category TOC

```dataviewjs
for (let entry of dv.pages("#ingredient and -#toc").groupBy(p => p.category)) {
    dv.header(2, entry.key);
    dv.list(entry.rows.map(p => [p.file.link]))
}
```

Auto-update and look like this:

1 Like

Matthias, you’re an Artist. One of these days you will code/script yourself right into someone’s heart :smiley:

I am very grateful for you helping and teaching me! See DM

2 Likes

At first glance, two questions rise that I think are important:

  • Which plugins do I need to have installed to make this work?
    • I suppose Dataview, is DataviewJS a separate plugin or does it work off of the Dataview plugin?
    • I googled and I assume it’s just the Dataview plugin being able to do javascript because it has a javascript API. Is my assumption correct?
  • I have Obsidian Query installed, should I uninstall it or does it not interfere with Dataview/DataviewJS ? I have used in in some notes so I hope it doesn’t interfere.

Good questions!

Yes, mylady!

It shouldn’t interfere in any way, so you can leave it installed and happily use it.

In general, Templater and Dataview are good companions, so I’d advise to have both installed.

For more fun, here are my current testing templates for “ingredients” and “recipes”. I also include a zipped-up “Recipes” folder that one could use as a starting example. :slight_smile:

“ingredients” template

---
ingredient: name

# Units of count, mass, volume – Use array of valid units from:
# pce, g, kg, ml, l, tsp, tbsp, fl oz, cup, pt, qt, gal
units: [pce, g, kg]

# Category – One of:
# legumes, fruit, tubers, vegetables, fungi, nuts, seeds, breads,
# dairy, meat, eggs, cereals, rice, fish, shellfish, other
category: other

GI: 0  # glycemic index
CH: 0  # carbohydrates in g per 100 g
GL: 0  # per 100g (= GI * CH/100))
cal: 0  # calories per 100 g

# Tags – Use "ingredient" and the category
tags: [ingredient, other]
---

# `=this.ingredient`

Category: `=this.category`

| Glycemic index | Carbohydrates\* | Glycemic load\* | Calories\*  |
| -------------- | --------------- | --------------- | ----------- |
| `=this.GI`     | `=this.CH` g    | `=this.GL`      | `=this.cal` |

<small>\* per 100 g</small>

### Notes

… description, notes …

### Used in these recipes

```dataviewjs
dv.list(dv.pages('"Recipes" and #recipe and -#toc')
    .where(p => p.recipe && p.ingredients.map(e => e[0])
        .indexOf(dv.current().ingredient) >= 0)
    .file.link
);
```

“recipe” template

---
recipe: Name

# Category - Use one of:
# appetizers, condiments, confectionary, desserts, dips, pastes,
# spreads, dried, dumplings, fast food, fermented foods, noodles,
# pies, salads, sandwiches, sauces, snacks, soups, stews, other
category: other

servingsize: 100 g # blank-separated, so "unit" can be split

# Adjust portions to automatically modify recipe
portions: 4

# use standard durations here
preparationtime: 0 min
cookingtime: 0 min
totaltime: 0 min

# Ingredients should be named like their note (for making links)
# Quantities are always per PORTION.
# Don’t use [[link]] syntax here, might break the YAML!
# Units: pce, g, kg, ml, l, tsp, tbsp, fl oz, cup, pt, qt, gal
ingredients:
  - ["sugar, white", 20 g]
  - [watermelon, 80 g]

# Tags – Use "recipe", "food" or "drink", and the category
tags: [recipe, food, other]
---

# `=this.recipe`

Category: `=this.category`

## Ingredients for `=this.portions` portions (`=this.servingsize` ea.)

```dataviewjs
var i;
var list = [];
for (i=0; i < dv.current().ingredients.length; i++) {
    var name = dv.current().ingredients[i][0];
    var amount = dv.current().ingredients[i][1].split(" ")[0];
    var unit = dv.current().ingredients[i][1].split(" ")[1];
    var link = '[[' + name + ']]'
    list.push(amount * dv.current().portions + " " + unit + " " + link);
}
dv.list(list);
```

## Nutritional values

… some dataviewjs to calculate totals from the ingredients, maybe combined GL, carbohydrates, Insulin Index, or the like …

## Preparation

Preparation: `=this.preparationtime` Cooking/baking: `=this.cookingtime` Total: **`=this.totaltime`**
<!-- entries separated by U+2003 emspace, U+00A0 nbsp between label & value -->

… preparation …

## Notes

… notes …

“Recipes” and subfolders (zipped)

Recipes.zip (13.2 KB)

2 Likes

Important to know for a beginner (we Dataview junkies already know that): Dataview lists and tables will not populate the graph view or tags list, because everything is dynamically generated.

2 Likes