ENikS/LINQ

Left join Faild

Closed this issue · 5 comments

import { asEnumerable as linq } from 'linq-es5';

const yx = [
    { id: '1', batchNumber: 'ZKFM1' },
    { id: '2', batchNumber: 'ZKFM' },
    { id: '3', batchNumber: 'ZKFM1' }
];
const zx = [
    { id: '1', value: 'zzz' },
    { id: '2', value: 'xxx' },
];

// LEFT JOIN
const yyy = linq(yx).GroupJoin(zx, a => a.id, b => b.id, (a, temp) => ({ a, temp }))
    .SelectMany((t1: any) => linq(t1.temp).DefaultIfEmpty(), (t1: any, t: any) =>
        ({
            id: t1.a.id,
            batchNumber: t1.a.batchNumber,
            value: t == null ? null : t.value,
        }))
    .ToArray();
console.log(JSON.stringify(yyy));

the answer as blow:

[
    {
        "id": "1", 
        "batchNumber": "ZKFM1", 
        "value": "zzz"
    }, 
    {
        "id": "2", 
        "batchNumber": "ZKFM", 
        "value": "xxx"
    }
]

i hope it will be:

[
    {
        "id": "1", 
        "batchNumber": "ZKFM1", 
        "value": "zzz"
    }, 
    {
        "id": "2", 
        "batchNumber": "ZKFM", 
        "value": "xxx"
    }, 
    {
        "id": "3", 
        "batchNumber": "ZKFM1", 
        "value": null
    }
]

import { asEnumerable as linq } from 'linq-es5';
import { asEnumerable as linq } from 'linq-es2015';

both have the same result.

ENikS commented

Key should not be composite object

In C# code, the same left join code as below:

var yx = new[]
{
    new { id= "1", batchNumber= "ZKFM1" },
    new { id= "2", batchNumber= "ZKFM" },
    new { id= "3", batchNumber= "ZKFM1" }
};
var zx = new[] 
{
    new { id= "1", value= "zzz" },
    new { id= "2", value= "xxx" },
};

// LEFT JOIN
var yyy = yx.GroupJoin(zx, a => a.id, b => b.id, (a, temp) => new { a, temp })
    .SelectMany(t1 => t1.temp.DefaultIfEmpty(), (t1, t) => new
    {
        id = t1.a.id,
        batchNumber = t1.a.batchNumber,
        value = t?.value,
    })
    .ToArray();
foreach (var item in yyy)
{
    Console.WriteLine(JsonConvert.SerializeObject(item));
}

the result is:

{"id":"1","batchNumber":"ZKFM1","value":"zzz"}
{"id":"2","batchNumber":"ZKFM","value":"xxx"}
{"id":"3","batchNumber":"ZKFM1","value":null}

what's the useage of linq-es5 or linq-es2015?

ENikS commented

Good catch! Thank you!

linq-es5 compatible with old Node. linq-es2015 compatible with latest EcmaScript-2015

Hi' I just run the code OP has posted and i'm still getting 2 columns instead of 3.
To fix it, Instead of using .DefaultIfEmpty() i just return an [0] for temp instead (during groupjoin transform).

Also, for anyone interested, I extracted the code into a leftOuterJoin function

function leftOuterJoin(a, b, sel, transform) {
  //a is assumed to already be Enumerable
  return a.GroupJoin(b, sel, sel, (it, t) => ({it, t: t || [0]}))
    .SelectMany(i => i.t, ({it}, s) => transform(it,s));
}

So the example above becomes:

const result = leftOuterJoin(linq(yx), zx, it => it.id, (a,b) => ({
  id: a.id,
  batchNumber: a.batchNumber,
  value: b.value,
})).ToArray();

@ENikS I assume you wouldn't want to implement leftOuterJoin directly on the Enumerable, since it's not part of LINQ, but perhaps it's worth adding it to documentation?