简体   繁体   中英

Need assitance with matching JSON files

I am pretty new to JSON and JS and I am hoping someone can help me out. I am working with two separate JSON files. The recipe JSON file has an ID field and an ingredientNum field. In my second JSON file, I need to match the ingredientNum from the first JSON file with the corresponding field in the second JSON file called itemFullUPC . If there is a match in the fields, I need to replace the current ingredientNum that is displayed on the page in the unordered list with the itemName from the second JSON file that corresponds to the correct itemUPC. Below are the databases and my code. Hope someone can help me out!

Recipe JSON Example:

[
    {
          "recipeName":"Test",
          "id":"10",    
          "ingredients":[
             {
                "ingredientNum":"070796501104",
                "ingredientMeasure":"1 bottle",
                "ingredientMisc1":"(33.8 fl oz)"
             },
             {
                "ingredientNum":"070796000164",
                "ingredientMeasure":"1/2 cup",
                "ingredientMisc1":""
             }
          ]
    }
]

Product JSON Example:

 [
        {
              "productName":"Tomatoes",
              "itemFullUPC":"070796501104"
        },
        {
              "productName":"Cherries",
              "itemFullUPC":"070796000164"
        }
]

For example, in the second database. The productName called "Cherries" has the same number in the first database, I need to replace the list that is currently generated on the page with the item names.

Expected Output

  • 6-8 oz 070796501104 will become 6-8 oz Tomatoes
  • 1/4 tsp 070796000164 will become 1-4 tsp Cherries

I need to do this for the whole list or anything the matches. I have included my attempt below thanks.

$(document).ready(function() {

     'use strict';

     $.ajax({
        url: 'path to recipeDB',
        cache: true,
        success: function(data){
           data = data.replace(/\\n/g, "\\n")
                     .replace(/\\'/g, "\\'")
                     .replace(/\\"/g, '\\"')
                     .replace(/\\&/g, "\\&")
                     .replace(/\\r/g, "\\r")
                     .replace(/\\t/g, "\\t")
                     .replace(/\\b/g, "\\b")
                     .replace(/\\f/g, "\\f");
           data = data.replace(/[\u0000-\u0019]+/g,"");

         var json = JSON.parse(data);

         $.ajax({
            dataType: "jsonp",
            url: 'path to itemDB',
            cache: true,
            success: function(itemData){
                var product_data = itemData;

                var productUPC = '';
                var productName = '';

                $.each(product_data, function(i, item) {
                        productUPC += item.itemFullUPC;  
                        productName += item.itemName;
                });

         var ingredients = '';

         $.each(json, function(i, item) {
             if (item.id == "10") {
                ingredients += '<ul>';
                 for (var i = 0; i < item.ingredients.length; i++) {
                         ingredients += '<li>' + item.ingredients[i].ingredientMeasure + ' ' + item.ingredients[i].ingredientNum + ' ' + item.ingredients[i].ingredientMisc1 + '</li>'; 
                 }
                ingredients += '</ul>'; 
             } 
         });

         $('#recipeIngredients').html(ingredients);

         }
         });
     }
     });
});

I successfully have the list working from the first database but I am not sure how to link to the second database and change the items from showing UPC in the list to the item name.

You can use Array.prototype.map() and Array.prototype.find()

 var recipe = [{ "recipeName": "Test", "id": "10", "ingredients": [{ "ingredientNum": "070796501104", "ingredientMeasure": "1 bottle", "ingredientMisc1": "(33.8 fl oz)" }, { "ingredientNum": "070796000164", "ingredientMeasure": "1/2 cup", "ingredientMisc1": "" }] }]; var product = [{ "productName": "Tomatoes", "itemFullUPC": "070796501104" }, { "productName": "Cherries", "itemFullUPC": "070796000164" }]; recipe.ingredients = recipe[0].ingredients.map(function(o) { o.ingredientName = product.find(function(p) { return p.itemFullUPC === o.ingredientNum; }).productName; return 0; }); console.log(recipe);

The solution using Array.prototype.forEach() and Array.prototype.some() functions:

 var recipes = [{"recipeName":"Test","id":"10","ingredients":[{"ingredientNum":"070796501104","ingredientMeasure":"1 bottle","ingredientMisc1":"(33.8 fl oz)"},{"ingredientNum":"070796000164","ingredientMeasure":"1/2 cup","ingredientMisc1":""}]}], products = [{"productName":"Tomatoes","itemFullUPC":"070796501104"},{"productName":"Cherries","itemFullUPC":"070796000164"}]; recipes[0].ingredients.forEach(function (recipe) { products.some(function (product) { var cond = product.itemFullUPC === recipe.ingredientNum; if (cond) { recipe.ingredientNum = product.productName; } return cond; }); }); console.log(recipes);

Now, you can iterate through the recipe ingredients and fill the unordered list

Assuming you have an array of recipes, you can remap the array like this:

 var recipes = [{ "recipeName": "Test", "id": "10", "ingredients": [{ "ingredientNum": "070796501104", "ingredientMeasure": "1 bottle", "ingredientMisc1": "(33.8 fl oz)" }, { "ingredientNum": "070796000164", "ingredientMeasure": "1/2 cup", "ingredientMisc1": "" }] }] var ingredients = [{ "productName": "Tomatoes", "itemFullUPC": "070796501104" }, { "productName": "Cherries", "itemFullUPC": "070796000164" }] recipes = recipes.map(function(recipe) { return $.extend(recipe, { ingredients: recipe.ingredients.map(function(ingr) { return $.extend(ingr, { productName: ingredients.find(function(el) { return ingr.ingredientNum == el.itemFullUPC; }).productName || "" }); }) }); }); console.log(recipes);
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

I would change the products array over to an object so you do not have to keep looping over it to find the products. If you can change the server to return an object with keys instead of an array, that would be a bonus.

 var recipe = [{ "recipeName": "Test", "id": "10", "ingredients": [{ "ingredientNum": "070796501104", "ingredientMeasure": "1 bottle", "ingredientMisc1": "(33.8 fl oz)" }, { "ingredientNum": "070796000164", "ingredientMeasure": "1/2 cup", "ingredientMisc1": "" }] }]; var products = [{ "productName": "Tomatoes", "itemFullUPC": "070796501104" }, { "productName": "Cherries", "itemFullUPC": "070796000164" }]; //change products to object for easier lookup var prodHash = products.reduce(function(o, item) { o[item.itemFullUPC] = item.productName; return o; }, {}); var ingredients = recipe[0].ingredients.map(function(item) { return "<li>" + item.ingredientMeasure + (item.ingredientMisc1.length ? " " + item.ingredientMisc1 + " " : " ") + prodHash[item.ingredientNum] + "</li>"; }).join(""); document.getElementById("out").innerHTML = ingredients;
 <ul id="out"></ul>

first a sidenote:

//these don't do anything, you're literally replacing these strings with the very same strings
data = data.replace(/\\n/g, "\\n")
    .replace(/\\'/g, "\\'")
    .replace(/\\"/g, '\\"')
    .replace(/\\&/g, "\\&")
    .replace(/\\r/g, "\\r")
    .replace(/\\t/g, "\\t")
    .replace(/\\b/g, "\\b")
    .replace(/\\f/g, "\\f");

//and these should usually not be in the JSON-string
data = data.replace(/[\u0000-\u0019]+/g, "");

so to the code:

$(document).ready(function() {
    'use strict';

    //first let's make the ajax-calls parallel
    $.when(
        $.ajax({
            dataType: "jsonp",
            url: 'path to recipeDB',
            cache: true
        }),

        $.ajax({
            dataType: "jsonp",
            url: 'path to itemDB',
            cache: true
        })
    ).then(function(recipes, products){

        //now let's convert the products into a more useful structure
        var productsByUPC = products.reduce(function(acc, item){
            acc[ item.itemFullUPC ] = item.productName;
            return acc;
        }, {});

        //a sinple utility
        //and don't be shy to use long and speaking names
        //it's not your task to minify your code, it'the minifiers task
        //and due to autocompletition one can not even brag about having to much to type
        function formatIngredientAndAddName( ingredient ){
            //here it makes no sense to add "ingredient" to each property name
            //do you think, that `ingredient.ingredientMeasure`
            //has any benefit over `ingredient.measure`
            return {
                name: productsByUPC[ ingredient.ingredientNum ],
                measure: ingredient.ingredientMeasure,
                misc: ingredient.ingredientMisc1
            }
        }           

        //and clean up the recipes
        return recipes.map(function(recipe){
            return {
                id: recipe.id,
                name: recipe.recipeName,
                ingredients: recipe.ingredients.map( formatIngredientAndAddName )
            }
        });

    }).then(function(recipes){
        //now we have some clean data, containing all we need, 
        //let's create some markup

        function ingredient2Markup(ingredient){
            return '<li>'
                + ingredient.measure
                + ' '
                + ingredient.name
                + ' '
                + ingredient.misc1
                + '</li>';                  
        }

        function recipe2Markup(recipe){
            return '<ul>' +
                recipe.ingredients
                    .map( ingredient2Markup )
                    .join("")
            +'</ul>';
        }

        $('#recipeIngredients').html( 
            recipes.map( recipe2Markup ).join("\n") 
        );
    })
});

Edit:

the recipe data set is actually a php file that is formatted as an array so i cant use json p

I used jsonp there because the other request also was jsonp.

<?php
    //... your php file

    //json
    $output = json_encode( $yourDataStructure );
    $contentType = 'application/json';

    //optional jsonp output
    if(!empty( $_GET['callback'] )){
        $contentType = 'application/javascript';
        $output = $_GET['callback'] . '(' . $output . ')';
    }

    //setting the correct Content-Type
    //and will throw if you already started sending something besides 
    header('Content-Type: ' . $contentType);

    //ensure that this is the last/only thing that is sent to the client
    exit( $output );
?>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM