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

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

In my case, Dataview and Templater are fine as they are, I do not need Graph View for what I want to accomplish. The many variables there will be in what I want to build, changing in every case, ask for something strong like Dataview and Templater that give me predictable outcome time and again. I just don’t like calculating all that by hand and breaking my brain over it, when that’s not necessary :slight_smile:

Graph View is very useful for me BEFORE I put in all the variables, perhaps finding connections I didn’t see before.

Essentially, what I am trying to build is some form of “Life Assistance” thingy, that takes whatever data I have on food, exercise, mental coping mechanisms on the one hand, and on the other hand a specific person’s physical or mental complaints and spits out a range of different and perhaps synergetic “actions” this person could try to improve their health. Of course this will never be an official medical advice, always consult your doctor before incorperating anything into your life that comes out of the Life Assistance.

I am not sure I can pull this off, but I am confident that I can at least build a Recipe Database to begin with. With @Moonbase59 's help :smiley:

How many <3 <3 <3 <3 <3 would fit in this little typing window?? THANKS a bunch for the .zip !!!

Paprika has an (undocumented) API. I wonder if it’s worth making a plugin to sync recipes?

2 Likes

Hi Jeremy! Your name was already brought to my attention by Matthias :slight_smile:

Your suggestion is making my mind go in overdrive haha!

  • Obsidian, once you get the hang of it, is super easy to work with and type stuff into. Easier than entering everything in Paprika. Mostly because I think I can convert everything I already have (as .txt, .pdf, .docx and .html) with the help of Obsidian and Pandoc (still need to learn that, but I know it can be done) so no retyping needed, just some cleaning up perhaps.

  • Paprika is a real cool recipe manager, with many features I probably don’t need in the recipes in Obsidian and it has an iOS version that syncs almost realtime. So easy to be able to use my iPad as a cookbook in the kitchen on its own standard, it even has an option to keep the screen from going dark while you are cooking.

So, since both have their own unique possibiities,

  • YES, a syncing plugin would be EXTREMELY cool to have :smiley: !

=> but someone else who is smart and willing to give it time, would need to do that, because I am by no means skilled enough in that area.

Do you think it would be very difficult and time consuming?

Okay, a little update here about what I have been doing with the Recipes, for those interested. It’s also a #remindertoself (which I - of course - also put into my “Build Recipe “database” in Obsidian”-note which lives in my vault.

Sure enough, I want Recipes as a whole, to be in Dutch. After all, that’s my language. So, I needed to figure out what I could change without the risk of breaking everything. Which of course happened, to a n00b like myself :stuck_out_tongue: . Like, at least 3 times :joy: Glad I left the zip in the vault, I have unpacked and started over also 3 times.

Anyway, the first time I unpacked Recipes.zip somewhere deep in my vault, where I eventually want it to end up. Oh boy! Nothing worked anymore. I checked your screenshots (the ones in this discussion, above) and saw you had the whole thing in the root of your vault.

So, 2nd try, I deleted my try & error Recipes folder and I unpacked Recipes.zip in the root of my vault, expecting it to work then. It did. Yay!!! I made some changes, like the word “recipe” is called “recept” in Dutch. I didn’t know if I could just change that everywhere, in markup and in Dataview(js) - but after a few errors, I got that working. Cmd-R proved to be my saviour quite a few times, after I initially thought I made a mistake. My godgiven cleverness :stuck_out_tongue: kicked in just in time to hit that combo and what do you know, voila! It worked after all. Pet on my own head :grin:

But then I wanted to change categories and other stuff and kaboom! it stopped working all over again and even Cmd-R didn’t save me this time. I didn’t delete everything, but I did unpack an extra instance of Recipes, for comparison. Should have done that straightaway - not so clever I didn’t do that :stuck_out_tongue: but at least I thought of it in time for round 3.

I managed to move Recipes from the root to 1 level higher up, closer to where I wanted it to be. And I discovered, that changing the path in the Dataview code in the -TOC notes, was enough to make it work. Yay!! It needed another hit on the Cmd-R, because it kept saying that the two recipe notes weren’t created yet and refreshing the note itself wasn’t enough, apparently. But who cares. I love Cmd-R :wink: !

Now comes the creepy part - moving it to its permanent (for now) place in my vault and not breaking it. Shouldn’t be so hard, I think. But I also want to rename Recipes into Recepten…ewww! although, my sense of logic tells me, that again the onnly place I will need to change that, is in the -TOC notes. Because as far as I can see, that is - at the moment - the only place the Dataview code needs a specific path.

Just for laughs, here is a piece of my own comments in my “Build Recipe “database” in Obsidian” note:

If I need to move the recipe database to another spot in the vault, I need to update some instances of the Dataview code, specifically in the -TOC notes. Because the Dataview code in those notes, points to where exactly should be searched for recipes. I figured that out all by myself, through trial and error :wink: - Javascript and other code is not all that straightaway obvious to me, being an alpha person. Even though it’s called a language! I assumed it would go through the entire vault, looking for recipes. But apparently, it does not :slight_smile: - it needs “directions”, so to speak.

So far my Recipes adventures :wink: - y’all are probably used to way shorter forum discussion messages, but hey - like I said, I am an alpha/language person, better with words than with code. I just don’t give up easily, and beta stuff like code and science and the like do have my interest, I only lack the talent for understanding it fast and in depth.

Very good so far!

I could actually run in whatever folder, only it did always pick up my Templates (in the templates folder) up, too, so I thought "let it start in some folder “Recipes” and take what’s there (and its subfolders).

The easy step is actually in the two “TOC” notes, just change

list
from "Recipes" and #food
where recipe
sort file.name asc

to wherever your starting folder is. Don’t forget to also change the tags like #food—you might have called it “spijs” or something. Should you also have changed the variable names in the YAML, like maybe “recipe: Melon Salad” to “recept: Meloen salade”, you also need to modify the “where” clause—it looks if a note contains a “recipe” variable.

Unfortunately the ingredients notes also contain dataviewjs code that needs to be changed in every one—we don’t yet have a better way, maybe code including will come some day, so we could reuse the same code.

Here’s an ingredient dataviewjs, to find in which recipes this ingredient is used:

```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
);
```

Change

  • "Recipes" to your new recepten start folder,
  • #recipe to your new tag word for recept,
  • -#toc to your new tag word for TOCs (to _ex_clude them from the search!)
  • p.recipe to your new YAML variable for the recipe: xxx entry, like p.recept
  • p.ingredients.map to your new YAML variable for ingredients, like p.ingrediënten.map (don’t know if non-ASCII works, though)
  • dv.current().ingredient to the new YAML variable for ingredient: xxx in the ingredients notes, like dv.current().ingrediënt

The good thing:

  • Since it’s the same code always, you can copy-paste

The bad thing:

  • You have to do this in all existing ingredients notes

And don’t forget to change the templates in the templates folder, too! (recipe and ingredient)

In the recipe template and all existing recipes, you need to change

  • all =this.something to = this.yourword
  • the dataviewjs code. You should now already have a good idea how, and I’ll leave this as an exercise. Please avoid typing mistakes, a wrong dot, bracket or lowercase/uppercase variation can break the whole thing! (Hint: ingredients, portions)

Have fun and let us now if things like ë and ij work in dataviewjs and Javascript variable names!

How much time the world could save if we all had just one language—for this little unimportant dirt ball we live on in a huge universe one language would be more than sufficient. We are all the same humans, after all. Sigh.

2 Likes

Hi :slight_smile: :blush:

Thanks for wrapping up the instances that need to be changed. I figured a lot of it out - which is imho the best way of learning, at least to begin with - and now I can go see if I can do it right. I like self-challenges. But I know when I need to ask for help :slight_smile: I will copy your last post into my vault so that I can check it easier.

I will let you know if non-ascii works! I was curious about that too, but left out the umlaut in ingredienten for now, to make sure it worked.

And yes…this tiny spot in the mighty vast universe is crazy. Or better put, the people on it. Humanity has done a crazy job of ruining the place. Too many fear-based, power-based creatures, brrrr. That is becoming quite obvious now with the whole covid thing. We for sure do not need 60 languages. One is more than enough. English has taken a big place in trying to become that one language and it’s good it’s there. But, over 100 years ago in 1887, L. Zamenhof already thought of that and invented Esperanto. There are still some 2 million people who speak it, nowadays. So easy to learn as a second language!

Mi deziras al vi tre belan tagon, Matiaso!

Hee hee, same to you! (I wish you a very beautiful day, she said.)

OT: In Dutch, is the diaeresis only used to separate vowels in a diphthong? So you could actually leave out this “pronounciation helper” officially? (Say, somehow like most modern Dutch writers don’t use the “ij” digraph anymore?)

1 Like

Super excited to see where this goes ! I would love to see the graph view when lots of recipes are added. I love the breakdown in the uploaded ZIP and im going to give it a try as well.

Data view is just great to open up the fridge, see what is in there and get pointed to the stuff you can make.

For preparing the food, there is the ‘presentation view’ that you can have a look at. You can also throw in images easily to make it nicer.

My recipes are currently stored in Google Keep so I’m going to look for some kind of bulk export.

1 Like