Search code examples
javascriptlinqlinq.js

How do I chain "SelectMany" calls with linqjs (or flatten JSON)


Using linq.js how can I chain two SelectMany calls together.

Given the following JSON structure:

[
    {
        "UpFrontCost": "29.95",
        "Currency": "USDAUD",
        "FittingDate": "2013-07-08 06:30:16Z",
        "Widgets": [
            {
                "ID": 3,
                "Name": "Test1"
            },
            {
                "ID": 4,
                "Name": "Test19"
            },
            {
                "ID": 6,
                "Name": "Test8"
            }
        ]
    },
    {
        "UpFrontCost": "29.95",
        "Currency": "USDAUD",
        "FittingDate": "2013-07-08 06:30:16Z",
        "Widgets": [
            {
                "ID": 67,
                "Name": "Test1"
            },
            {
                "ID": 99,
                "Name": "Test19"
            },
            {
                "ID": 34,
                "Name": "Test8"
            }
        ]
    }
]

I would like a list of all the "Widgets" (in this example a list of 6 widgets).


Solution

  • You don't need to really chain anything. Your root object is an array, you just want to select each widget for each object in that array.

    var query = Enumerable.From(jsonObject)
        .SelectMany("$.Widgets") // Select each widget found in the Widgets property
        .ToArray();
    

    To flatten that array of widgets attaching each property of the parent object to the result, there's a couple of ways you could do it. You can use a nested query using the function syntax.

    var query = Enumerable.From(jsonObject)
        .SelectMany(function (item) {
            return Enumerable.From(item.Widgets)
                .Select(function (widget) {
                    return {
                        ID: widget.ID,
                        Name: widget.Name,
                        UpFrontCost: item.UpFrontCost,
                        Currency: item.Currency,
                        FittingDate: item.FittingDate
                    };
                });
        })
        .ToArray();
    

    Or using the lambda string syntax:

    var query = Enumerable.From(items)
        .SelectMany("$.Widgets",
            // argument 1 ($) - the parent object
            // argument 2 ($$) - the selected object (a widget)
            "{ ID: $$.ID, Name: $$.Name, UpFrontCost: $.UpFrontCost, Currency: $.Currency, FittingDate: $.FittingDate }"
        )
        .ToArray();