3

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).

paligap
  • 942
  • 1
  • 12
  • 28

1 Answers1

3

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();
Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
  • Thanks Jeff. Is there anyway that I can return an array which contains properties from the parent and child (one row in the array for each child)? This is the actual use case for this question, at the moment I am solving it using two for loops and pushing data to an array manually. – paligap Jul 20 '13 at 00:29
  • Sure. Which properties did you want to include? The writing a selector, you can write it either as a string or a function. When writing as a string, you can use just normal javascript syntax. So you can create an object using the usual object initializer syntax. – Jeff Mercado Jul 20 '13 at 02:58
  • So in my example I would like to return an array containing some properties from the parent object (repeated for each child item) and some properties from the child. Essentially flattening the whole array, one row per child. – paligap Jul 20 '13 at 03:07
  • Thanks Jeff. The selection syntax is exactly what I was looking for. – paligap Jul 20 '13 at 03:51