Feature: Nutrition Facts
Present nutrition-related properties in a sensible collection, as per the original Datakick style:
NB "Percent of daily values" text at the bottom is derived /assumed and not part of the stored properties values.
NB Default units are not present in the data (and have to be assumed) - e.g. 'Trans Fat' (or trans_fat) is measured in g, whereas Cholesterol is measured in mg. In neither case is the unit stored in the data, with the properties stored as { "trans_fat":0.0, "cholesterol":0 }.
NB Some values are grouped and tallied, e.g. Saturated Fat, Trans Fat, etc are grouped and tallied as 'Total Fats'. The total value is present in the stored properties (as fat) - see * Example JSON Data* below.
NB Total calories and Calories from Fat are reported separately. This data is present in the stored properties (as fat) - see * Example JSON Data* below.
Example JSON Data
{"gtin14":"00000000079983","brand_name":"Trader Joe's","name":"Pistachios - Dry Roasted & Salted","size":"16 oz (1 lb) 454 g","ingredients":"Pistachios, Salt\r\n\r\nFACILITY PROCESSES OTHER TREE NUTS","serving_size":"1/4 cup nuts without shells (30 g / about 1/2 cup with shells)","servings_per_container":"about 8","calories":180,"fat_calories":120,"fat":14.0,"saturated_fat":1.5,"trans_fat":0.0,"polyunsaturated_fat":2.5,"monounsaturated_fat":10.0,"cholesterol":0,"sodium":160,"carbohydrate":9,"fiber":3,"sugars":3,"protein":6,"images":[]}
DEV NOTE
Might be worth look at passing queries through to Open Food Facts:
https://github.com/openfoodfacts/openfoodfacts-ruby
Looks like openfoodfacts use this as a basic RDF structure:
NB The URL for the schema seems to have disappeared, but can be found via the Wayback Machine
We can probably convert from the RDF format to JSON-LD fairly easily, e.g. using https://issemantic.net/rdf-converter:
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:food="http://data.lirmm.fr/ontologies/food#"
xmlns:dcterms="http://purl.org/dc/terms/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:void="http://rdfs.org/ns/void#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns:foaf="http://xmlns.com/foaf/0.1/">
<rdf:Description rdf:about="http://world-en.openfoodfacts.org/product/0000000000000207025004/andre" rdf:type="http://data.lirmm.fr/ontologies/food#FoodProduct">
<food:code>0000000000000207025004</food:code>
<food:name>Andrè</food:name>
<food:IngredientListAsText></food:IngredientListAsText>
<food:carbohydratesPer100g>65</food:carbohydratesPer100g>
<food:energyPer100g>690</food:energyPer100g>
<food:energyKcalPer100g>165</food:energyKcalPer100g>
<food:fatPer100g>2</food:fatPer100g>
<food:fiberPer100g>3</food:fiberPer100g>
<food:proteinsPer100g>1.5</food:proteinsPer100g>
<food:saturatedFatPer100g>2</food:saturatedFatPer100g>
<food:sugarsPer100g>12.6</food:sugarsPer100g>
</rdf:Description>
</rdf:RDF>
becomes
[
{
"@id": "http://world-en.openfoodfacts.org/product/0000000000000207025004/andre",
"@type": [
"http://data.lirmm.fr/ontologies/food#FoodProduct"
],
"http://data.lirmm.fr/ontologies/food#IngredientListAsText": [
{
"@value": ""
}
],
"http://data.lirmm.fr/ontologies/food#carbohydratesPer100g": [
{
"@value": "65"
}
],
"http://data.lirmm.fr/ontologies/food#code": [
{
"@value": "0000000000000207025004"
}
],
"http://data.lirmm.fr/ontologies/food#energyKcalPer100g": [
{
"@value": "165"
}
],
"http://data.lirmm.fr/ontologies/food#energyPer100g": [
{
"@value": "690"
}
],
"http://data.lirmm.fr/ontologies/food#fatPer100g": [
{
"@value": "2"
}
],
"http://data.lirmm.fr/ontologies/food#fiberPer100g": [
{
"@value": "3"
}
],
"http://data.lirmm.fr/ontologies/food#name": [
{
"@value": "Andrè"
}
],
"http://data.lirmm.fr/ontologies/food#proteinsPer100g": [
{
"@value": "1.5"
}
],
"http://data.lirmm.fr/ontologies/food#saturatedFatPer100g": [
{
"@value": "2"
}
],
"http://data.lirmm.fr/ontologies/food#sugarsPer100g": [
{
"@value": "12.6"
}
]
}
]
Though it looks like the structure of the JSON retrieved directly from OpenFoodFacts is slightly different, e.g. "sugarsPer100g" in the converted RDF maps to "sugars_100g" in the JSON (see https://world.openfoodfacts.org/api/v0/product/737628064502.json for an example).
We will need to pick a schema - I'm leaning towards the RDF-derived one at present.
Per brief discussion with people from OFF, it looks like the RDF model hasn't been worked on in ~ 10 years. JSON is the preferred data transfer model, but without a specific schema it'll be awkward fitting it into a JSON-LD graph.
The information re "structured data" on the OFF website is probably out of date, but does have some interesting links - including references back to schema.org:
https://wiki.openfoodfacts.org/Structured_Data
There is some good advice on how to make use of the data from the OFF site:
https://wiki.openfoodfacts.org/Reusing_Open_Food_Facts_Data
We also might be able to make use of the OFF taxonomies to provide translations of content, something we haven't even thought about up to this point:
https://github.com/openfoodfacts/openfoodfacts-server/tree/main/taxonomies