在LINQ.js中,你可以使用一系列方法来操作数组。以下是一些常见的LINQ.js数组方法:
教程:https://medium.com/swlh/data-manipulation-in-javascript-using-linq-f3759e00aceb
Enumerable.From(array):将普通数组转换为可查询的LINQ.js数组对象。Where(predicate):根据指定的条件选择数组中的元素。
∗
∗
w
h
e
r
e
(
p
r
e
d
i
c
a
t
e
:
(
e
l
e
m
e
n
t
:
T
,
i
n
d
e
x
:
n
u
m
b
e
r
)
=
>
b
o
o
l
e
a
n
)
:
I
E
n
u
m
e
r
a
b
l
e
<
T
>
;
∗
∗
**where(predicate: (element: T, index: number) => boolean): IEnumerable
var filteredArray = Enumerable.From(array).Where((x)=> x > 5).ToArray();
Select(selector):对数组中的每个元素应用指定的转换函数,返回一个新的数组。var transformedArray = Enumerable.From(array).Select((x)=> x * 2).ToArray();
var result = Enumerable.from(array)
.select((user, index) => ({
...user,
id: index + 1
}))
.toArray();
在linq.js中,select和where是用于查询和筛选数据的两个关键字。它们的区别如下:
1. Select:Select用于选择查询结果中的特定字段。它类似于SQL中的SELECT子句。使用Select关键字,你可以指定要从查询结果中返回的字段,并对这些字段进行转换或操作。例如,你可以使用Select来选择一个对象的某个属性,或者对查询结果进行计算或转换。
2. Where:Where用于根据条件筛选出符合条件的数据。它类似于SQL中的WHERE子句。使用Where关键字,你可以指定一个条件表达式,用来过滤查询结果中的数据。只有满足条件的数据才会被包含在结果中。
简而言之,Select用于选择特定字段并对其进行转换或操作,而Where用于筛选符合特定条件的数据。
下面是一个示例,演示如何在linq.js中使用Select和Where:
假设有一个包含学生信息的数组students,每个学生对象都有name和age两个属性。现在我们想选择年龄大于18岁的学生的姓名,可以使用以下代码:
var students = [
{ name: 'Alice', age: 19 },
{ name: 'Bob', age: 17 },
{ name: 'Charlie', age: 20 },
{ name: 'David', age: 18 }
];
var result = Enumerable.From(students)
.Where(function(student) {
return student.age > 18;
})
.Select(function(student) {
return student.name;
})
.ToArray();
console.log(result); // 输出: ["Alice", "Charlie"]
在上面的代码中,Where函数用于筛选出年龄大于18岁的学生,而Select函数用于选择学生的姓名。最后,ToArray函数将结果转换为一个数组,方便输出或进一步操作。
希望这个解释对你有帮助!如果有任何问题,请随时提问。
OrderBy(keySelector):按照指定的键选择器对数组进行升序排序。var sortedArray = Enumerable.From(array).OrderBy(function(x) {
return x;
}).ToArray();
OrderByDescending(keySelector):按照指定的键选择器对数组进行降序排序。var sortedArray = Enumerable.From(array).OrderByDescending(function(x) {
return x;
}).ToArray();
Reverse():反转数组中的元素顺序。var reversedArray = Enumerable.From(array).Reverse().ToArray();
Skip(count):跳过数组中的前几个元素。var skippedArray = Enumerable.From(array).Skip(2).ToArray();
Take(count):选择数组中的前几个或者前几条元素。var takenArray = Enumerable.From(array).Take(3).ToArray();
groupBy:指定的键进行分组。公式
groupBy(
keySelector: (element: T) => TKey,
elementSelector: (element: T) => TElement,
resultSelector: (key: TKey, element: IEnumerable) => TResult, compareSelector: (element: TKey) => TCompare): IEnumerable;
let arr = [{ id: 1, name: '' }, { id: 2, name: '测试2' }, { id: 3, name: '测试3' }, { id: 4, name: '测试4' }]
const cdrev = Enumerable.from(arr)
.where(
(c) =>
c.name
)
.groupBy(
(pet) => pet.id,
(pet) => pet,
(key, group) => ({
key: key,
receiveact: group.sum((p) => p.id),
})
)
.toArray();
下面逐步解释代码的作用:
创建一个包含对象的数组arr:
let arr = [{ id: 1, name: '' }, { id: 2, name: '测试2' }, { id: 3, name: '测试3' }, { id: 4, name: '测试4' }]
使用Enumerable.from方法将数组转换为可查询的对象:
const cdrev = Enumerable.from(arr)
使用where方法进行筛选,只包含name属性不为空的对象:
.where((c) => c.name)
使用groupBy方法按指定的键进行分组。这里使用id作为键:
.groupBy(
(pet) => pet.id,
(pet) => pet,
(key, group) => ({
key: key,
receiveact: group.sum((p) => p.id),
})
)
(pet) => pet.id 是分组的键,表示按照对象的id属性进行分组。(pet) => pet 是一个转换函数,它定义了每个分组中的元素应该是什么。(key, group) => ({ key: key, receiveact: group.sum((p) => p.id) }) 是一个聚合函数,它定义了如何聚合每个分组的结果。在这里,我们将分组的键作为key属性,然后计算每个分组中所有元素的id属性的和作为receiveact属性。最后,使用toArray方法将分组的结果转换为数组:
.toArray();
总结起来,给定一个包含对象的数组,该代码会筛选出name属性不为空的对象,并根据id属性对它们进行分组。然后,对每个分组中的元素进行聚合,生成一个包含key和receiveact属性的对象数组。希望这样的解释对你有帮助!
使用 linq.js,你可以使用 Enumerable.from() 方法将数组转换为可查询的对象,然后使用链式调用来过滤和筛选数据。
首先,你需要引入 linq.js 库。然后,你可以使用以下代码来重写你的循环:
// const iftypetwolist = [];
// for (let i = 0; i < list.length; i++) {
// const it = list[i];
// if (it.children && it.children.length == 0 && it.ftype == 2) {
// iftypetwolist.push(it.taskmanagerid);
// iftypetwolist.push(it.taskacterid);
// }
// }
import * as Enumerable from 'linq';
const iftypetwolist = Enumerable.from(list)
.where(it => it.children && it.children.length === 0 && it.ftype === 2)
.selectMany(it => [it.taskmanagerid, it.taskacterid])
.distinct()
.where(it => it !== 0 && it.toString() !== 'null')
.orderBy(it => it)
.toArray();
在上面的代码中,Enumerable.from(list) 将 list 数组转换为可查询的对象。然后,使用 where() 方法来过滤数据,只保留满足条件的元素。接下来,使用 selectMany() 方法来选择并展开每个元素的 taskmanagerid 和 taskacterid 属性,并将它们放入一个新的数组中。然后,使用 distinct() 方法来去重,保留唯一的元素。接着,使用 where() 方法来过滤掉值为 0 或字符串为 ‘null’ 的元素。最后,使用 orderBy() 方法来对数组进行排序,并使用 toArray() 方法将查询结果转换回数组形式。
现在,iftypeonelist 和 iftypetwolist 数组将包含符合条件的元素,并且已经去重、过滤和排序,与你的原始循环的结果相同。
distinct() 方法来去重,条目10有案例
g
r
o
u
p
B
y
<
T
K
e
y
,
T
E
l
e
m
e
n
t
,
T
R
e
s
u
l
t
,
T
C
o
m
p
a
r
e
>
(
k
e
y
S
e
l
e
c
t
o
r
:
(
e
l
e
m
e
n
t
:
T
)
=
>
T
K
e
y
,
e
l
e
m
e
n
t
S
e
l
e
c
t
o
r
:
(
e
l
e
m
e
n
t
:
T
)
=
>
T
E
l
e
m
e
n
t
,
r
e
s
u
l
t
S
e
l
e
c
t
o
r
:
(
k
e
y
:
T
K
e
y
,
e
l
e
m
e
n
t
:
I
E
n
u
m
e
r
a
b
l
e
<
T
E
l
e
m
e
n
t
>
)
=
>
T
R
e
s
u
l
t
,
c
o
m
p
a
r
e
S
e
l
e
c
t
o
r
:
(
e
l
e
m
e
n
t
:
T
K
e
y
)
=
>
T
C
o
m
p
a
r
e
)
:
I
E
n
u
m
e
r
a
b
l
e
<
T
R
e
s
u
l
t
>
;
groupBy
var array = [
{id: 1, name: 'Order 1', product: 'Ford'},
{id: 1, name: 'Order 1', product: 'BMW'},
{id: 2, name: 'Order 2', product: 'Toyota'},
{id: 2, name: 'Order 2', product: 'Skoda'},
{id: 2, name: 'Order 2', product: 'Fiat'}
];
var result = Enumerable.from(array)
.groupBy(
g => g.name,
element => element,
(key, items) => ({key, items: items.toArray()}
)).toArray()
.groupBy(
g => ({ g.name, g.id })),
element => element,
(key, items) => ({key, items: items.toArray()}
)).toArray();
这段代码是使用Vue.js中的groupBy函数对一个数组进行分组操作。
groupBy函数接受三个参数:一个用于分组的键函数、一个用于选择分组元素的函数和一个用于处理每个分组的函数。
第一个参数(pet) => pet.id是一个箭头函数,它定义了如何从数组中的每个元素中提取一个键。在这个例子中,我们使用pet.id作为键来分组。
第二个参数(pet) => pet是一个箭头函数,它定义了如何选择分组元素。在这个例子中,我们选择了整个pet对象作为分组元素。
第三个参数(key, group) => ({ key: key, receiveact: group.sum((p) => p.id) })是一个箭头函数,它定义了如何处理每个分组。在这个例子中,我们创建了一个新的对象,其中包含两个属性:key和receiveact。
key属性是分组的键,它的值是第一个参数(pet) => pet.id提取的键。
receiveact属性是对每个分组中的元素进行求和操作的结果。在这个例子中,我们使用了group.sum((p) => p.id)来计算每个分组中pet.id的总和。
总结一下,这段代码的作用是将一个数组按照pet.id进行分组,并计算每个分组中pet.id的总和。最终返回一个包含分组键和总和的对象数组。
let arr = [
{ id: 1, name: '测试1' },
{ id: 2, name: '测试2' },
{ id: 3, name: '测试3' },
{ id: 4, name: '测试4' },
];
const cdrev = Enumerable.from(arr)
.where((c) => {
if (c.name) {
return c;
}
})
.groupBy(
(pet) => pet.name,//选择以哪个键分组
(pet) => pet,
(key, group) => ({
key: key,//此时的key等于 pet.name
receiveact: group.sum((p) => p.id),
})
)
.toArray();
//以下代码自动返回对象
.groupBy(
(pet) => pet.billid,
(pet) => pet,
(key, group) => ({
key: key,
fname: '',
billno: '',
pid: 0,
fcount: group.count(),
plantotal: ~~group.sum((p) => p.plantotal),
plantotalaftertax: ~~group.sum((p) => p.plantotalaftertax),
invoicetotal: ~~group.sum((p) => p.invoicetotal),
invoicetotalaftertax: ~~group.sum((p) => p.invoicetotalaftertax),
receiveact: 0,
receiveactaftertax: 0,
percent: 0,
})
)
//第二种请概况,也可以只构建分组
let result = Enumerable.from(arr)
.groupBy((item: any) => item.bigarea)
.select((group) => ({
bigarea: group.key,
questionid: id,
childern: group
.groupBy((item: any) => item.city)
.select((cityGroup: any) => ({
city: cityGroup.key,
childern: cityGroup
.groupBy((it: any) => it.brand)
.select((ftypeGroup: any) => ({
brand: ftypeGroup.key,
plannedNum: ftypeGroup.count(),
childern: ftypeGroup.toArray(),
}))
.toArray(),
}))
.toArray(),
}))
.toArray();
const allQuestionnaireUserList = Enumerable.from(allQuestionnaireUser)
.groupBy((item: any) => item.questionid)
.toObject(
(group) => group.key,
(group) => group.toArray()
);
//分组后设置,属性名
// [
// { ftype: 1, name: '1111' },
// { ftype: 1, name: '2222' },
// { ftype: 2, name: '333333' },
// ];
let groupedByFtype = Enumerable.from(rawData.value)
.groupBy((x: any) => x.ftype)
.select((g: any) => ({
ftype: g.key,
children: g.toArray(),
}))
.toArray();
//原来数组
const originalArray = [
{ id: 1, name: '222' },
{ id: 2, name: '3333' },
{ id: 1, name: 333 },
];
//结果对象
{
1: [{ id: 1, name: '222' },{ id: 1, name: 333 }],
2: [{ id: 2, name: '3333' }],
}
const allQuestionnaireUserList = Enumerable.from(allQuestionnaireUser)
.groupBy((item: any) => item.id)
.toObject(
(group) => group.key,
(group) => group.toArray()
);
let ftypeArr = [];
for (let i = 0; i < groupedByFtype.length; i++) {
const el = groupedByFtype[i];
let obj = { label: '', value: i + 1 };
obj.label = el.ftype;
ftypeArr.push(obj);
}
let ftypeArr = Enumerable.range(0, groupedByFtype.length)
.select((i) => {
let el = groupedByFtype[i];
return { label: el.ftype, value: i + 1 };
})
.toArray();
使用LINQ.js实现上述代码可以按照以下步骤进行:
1. 首先,确保已经引入了LINQ.js库。
2. 使用LINQ.js的`Enumerable.Range`方法创建一个从0到`groupedByFtype.length - 1`的整数序列。
3. 使用`Enumerable.Select`方法对整数序列进行映射,将每个整数`i`转换为一个包含`label`和`value`属性的对象。
4. 在映射函数中,设置`label`属性为`groupedByFtype[i].ftype`,设置`value`属性为`i + 1`。
5. 使用`Enumerable.ToArray`方法将LINQ查询结果转换为数组。
下面是使用LINQ.js实现的代码:
```javascript
let ftypeArr = Enumerable.Range(0, groupedByFtype.length)
.Select(i => {
let el = groupedByFtype[i];
return { label: el.ftype, value: i + 1 };
})
.ToArray();
```
这样,你就可以使用LINQ.js来实现相同的功能了。
// let arr = [];
// for (let i = 0; i < typePullDownList.value.length; i++) {
// const el = typePullDownList.value[i];
// if (el.value == e) {
// arr = el.children;
// break;
// }
// }
// let cityArr = Enumerable.from(arr)
// .groupBy((x: any) => x.city)
// .select((g: any) => ({
// city: g.key || '未设置城市',
// children: g.toArray(),
// }))
// .select((el, i) => ({
// label: el.city,
// value: i + 1,
// children: el.children,
// }))
// .toArray();
let cityArr = Enumerable.from(typePullDownList.value)
.where((el) => el.value == e)
.selectMany((el) => el.children)
.groupBy((x: any) => x.city)
.select((g: any) => ({
city: g.key || '未设置城市',
children: g.toArray(),
}))
.select((el, i) => ({
label: el.city,
value: i + 1,
children: el.children,
}))
.toArray();
解释: 在这个合并后的代码中,我们首先使用`where`方法筛选出`typePullDownList.value`中`value`属性等于`e`的元素。然后,我们使用`selectMany`方法将这些元素的`children`属性展开为一个扁平的数组。接下来,我们使用`groupBy`将数组按照`city`属性进行分组。然后,我们使用`select`将每个分组转换为一个对象,其中包含`city`和`children`属性。接着,我们使用`select`将每个对象转换为一个新的对象,其中包含`label`、`value`和`children`属性。最后,我们使用`toArray`将结果转换为一个数组。
请注意,我们还添加了一个条件来检查`city`属性是否存在,如果不存在,则将其设置为'未设置城市'。这样可以确保在没有城市属性的情况下,仍然可以正确地生成结果数组。
let name;
for (let i = 0; i < typePullDownList.value.length; i++) {
const element = typePullDownList.value[i];
if (element.value == typePullDownId.value) {
name = element.label;
break
}
}
使用LINQ.js可以将上述代码转换为以下形式:
```javascript
let name = Enumerable.From(typePullDownList.value)
.Where(element => element.value == typePullDownId.value)
.Select(element => element.label)
.FirstOrDefault();
```
这里的`Enumerable.From`方法将数组`typePullDownList.value`转换为一个可查询的集合。然后使用`Where`方法筛选出`value`属性等于`typePullDownId.value`的元素。接着使用`Select`方法选择`label`属性,并最后使用`FirstOrDefault`方法获取第一个匹配的元素的`label`属性值。
请确保在使用LINQ.js之前先引入该库。
itemsmineidarr.value = Enumerable.from(datamod)
.select('tid') // 选择'tid'属性
.distinct() // 去重
.toArray(); // 转换为数组
var array = [
{name: 'ondrej', lastname: 'hlouzek', age: 38},
{name: 'jakub', lastname: 'hlouzek', age: 39}
];var result = Enumerable.from(array)
.orderBy(o => o.name)
.first();
var array = [
{name: 'ondrej', lastname: 'hlouzek', age: 38},
{name: 'jakub', lastname: 'hlouzek', age: 39}
];var result = Enumerable.from(array)
.orderBy(o => o.name)
.last();
var array = [
{name: 'ondrej', lastname: 'hlouzek', age: 38}
];
var result = Enumerable.from(array)
.single();
var array = [
{name: 'Order 1', cost: 15233},
{name: 'Order 2', cost: 33533},
{name: 'Order 3', cost: 23511},
{name: 'Order 4', cost: 11244},
{name: 'Order 5', cost: 44432}
];
var result = Enumerable.from(array)
.orderBy(o => o.cost)
.take(2)
.toArray();
c o n t a i n s ( v a l u e : T ) : b o o l e a n ; contains(value: T): boolean; contains(value:T):boolean;
//查找array中documentNumber在numbers中的数据
var array = [
{documentNumber: '140710', createdDate: '2019-11-01', contract: '', total: 242.64, reference: 'PRIMARK MILAN RCW LAURENCE TAYLOR'},
{documentNumber: '140352', createdDate: '2019-11-02', contract: 'PRI19/00050', total: 22865.90, reference: '***GF WHC***'},
{documentNumber: '140120', createdDate: '2019-11-02', contract: 'PRI19/00052', total: 17732.70, reference: '***GF WHC***'},
{documentNumber: '140117', createdDate: '2019-11-03', contract: 'PRI19/00011', total: 15982.80, reference: '***GF WHC***'},
{documentNumber: '139977', createdDate: '2019-11-04', contract: '', total: 7314.98, reference: '***FIRST FLOOR RCW&PERIMETER***'},
{documentNumber: '139976', createdDate: '2019-11-08', contract: 'PRI19/00028', total: 10147.23, reference: ''},
{documentNumber: '139971', createdDate: '2019-11-13', contract: '', total: 16285.72, reference: '***FIRST FLOOR CD ATRIUMS***'},
{documentNumber: '139968', createdDate: '2019-11-15', contract: '', total: 8111.79, reference: '***FIRST FLOOR B-FRAMES***'},
{documentNumber: '139817', createdDate: '2019-11-18', contract: 'PRI19/00052', total: 5190.59, reference: '***GF RCW&RET***'},
{documentNumber: '139617', createdDate: '2019-11-23', contract: 'PRI19/00052', total: 14378.54, reference: '*****GROUND FLOOR CD*****'}
];
var numbers = ['139976', '139971'];
var result = Enumerable.from(array)
.where(w =>
Enumerable.from(numbers).contains(w.documentNumber))
.toArray();
//结果:[ {documentNumber: '139976', createdDate: '2019-11-08', contract: 'PRI19/00028', total: 10147.23, reference: ''},
//{documentNumber: '139971', createdDate: '2019-11-13', contract: '', total: 16285.72, reference: '***FIRST FLOOR CD //ATRIUMS***'}]
a l l ( p r e d i c a t e : ( e l e m e n t : T ) = > b o o l e a n ) : b o o l e a n ; all(predicate: (element: T) => boolean): boolean; all(predicate:(element:T)=>boolean):boolean;
var array = [1, 2, 3, 4, 5];
var allGreaterThanZero = Enumerable.from(array)
.all(element => element > 0);
console.log(allGreaterThanZero); // 输出 true
g
r
o
u
p
J
o
i
n
<
T
I
n
n
e
r
,
T
K
e
y
,
T
R
e
s
u
l
t
>
(
i
n
n
e
r
:
I
E
n
u
m
e
r
a
b
l
e
<
T
I
n
n
e
r
>
,
o
u
t
e
r
K
e
y
S
e
l
e
c
t
o
r
:
(
o
u
t
e
r
:
T
)
=
>
T
K
e
y
,
i
n
n
e
r
K
e
y
S
e
l
e
c
t
o
r
:
(
i
n
n
e
r
:
T
I
n
n
e
r
)
=
>
T
K
e
y
,
r
e
s
u
l
t
S
e
l
e
c
t
o
r
:
(
o
u
t
e
r
:
T
,
i
n
n
e
r
:
I
E
n
u
m
e
r
a
b
l
e
<
T
I
n
n
e
r
>
)
=
>
T
R
e
s
u
l
t
,
c
o
m
p
a
r
e
S
e
l
e
c
t
o
r
?
:
(
o
b
j
:
T
)
=
>
T
K
e
y
)
:
I
E
n
u
m
e
r
a
b
l
e
<
T
R
e
s
u
l
t
>
;
groupJoin
var orders = [
{id: 1, name: 'Order 1'}
];
var orderItems = [
{ orderId: 1, product: 'Ford' },
{ orderId: 1, product: 'BMW' }
]
var result = Enumerable.from(orders)
.groupJoin(
Enumerable.from(orderItems),
pk => pk.id,
fk => fk.orderId,
(order, items) => ({...order, items: items.toArray()})
).toArray();
min(selector?: (element: T) => number): number;
max(selector?: (element: T) => number): number;
average(selector?: (element: T) => number): number;
count(predicate?: (element: T, index: number) => boolean): number;
sum(selector?: (element: T) => number): number;
可以将以下类型的aggfunc (selector ?: (element: T) => number): number聚合函数应用于IEnumerable集合:
min-返回集合中的最小值
Max -返回集合中的最大值
average-返回集合中的平均值
Count -返回集合中元素的个数
Sum -返回集合中元素的和
var orderItems = [
{ orderId: 1, product: 'Ford', cost: 10000 },
{ orderId: 1, product: 'BMW', cost: 30000 },
{ orderId: 2, product: 'Toyota', cost: 20000 },
{ orderId: 2, product: 'Skoda', cost: 8000 },
{ orderId: 2, product: 'Fiat', cost: 6000 }
]
var result = Enumerable.from(orderItems)
.groupBy(g => g.orderId)
.select(s => ({
orderId: s.key(),
max: s.max(m => m.cost),
min: s.min(m => m.cost),
avg: s.average(m => m.cost),
count: s.count(),
sum: s.sum(s => s.cost)
}))
.toArray();
效果图

c o n s t r e s u l t = E n u m e r a b l e . f r o m ( o r d e r s ) . m a x B y ( s = > s . t o t a l ) ; const result = Enumerable.from(orders) .maxBy(s => s.total); constresult=Enumerable.from(orders).maxBy(s=>s.total);
查询查找列(红色列)中的最大值,并返回整个行(黄色行)。

zip<U, TResult>(second: IEnumerable<U>, resultSelector: (first: T, second: U, index: number) => TResult): IEnumerable<TResult>
export const orders =
[
{ id: 1, name: 'Order 1', createdDate: '2020.8.1' },
{ id: 2, name: 'Order 2', createdDate: '2020.8.2' },
{ id: 3, name: 'Order 3', createdDate: '2020.8.5' },
{ id: 3, name: 'Order 3', createdDate: '2020.8.5' },
];
export const orderItems =
[
{ row: 1, cost: 20000 },
{ row: 2, cost: 30000 },
{ row: 3, cost: 40000 },
{ row: 4, cost: 50000 },
]
const result = Enumerable.from(orders)
.zip(orderItems, (left, right) => ({ ...left, ...right }))
.toArray();
Enumerable.from(array)
.forEach(f => console.log(`item ${f}`);
排序命令如下:
orderBy—第一个按升序排序的命令
orderbydescent—第一个按降序排序的命令
thenBy—下一个按升序排序的命令
thenbydescent—下一个按降序排序的命令
Enumerable.from(array)
.orderByDescending(o => o.lastname)
.thenBy(o => o.name)
.thenByDescending(o => o.age)
公式
join<TInner, TKey, TResult>(inner: IEnumerable<TInner>, outerKeySelector: (outer: T) => TKey, innerKeySelector: (inner: TInner) => TKey, resultSelector: (outer: T, inner: TInner) => TResult, compareSelector?: (obj: T) => TKey): IEnumerable<TResult>;
只有当记录存在于两端(集合、表)时,内部连接才返回数据。如果其中一侧或另一侧的记录缺失,则该记录将不会被返回。

.join命令用于实现内部连接。左右集合(表)的连接是使用主键和外键来解决的。只要在左侧和右侧找到匹配,就返回连接的记录。根据图片。左边是主键Id= 1,右边是外键OrderId = 1 pk 1 = fk 1。在这种情况下,返回两行,其中左侧根据右侧的行重复。这是一个类型1:N连接。
结果

左外连接是返回第一个集合的每个元素的连接,而不管它在第二个集合中是否有任何相关元素。您可以使用LINQ通过对组连接的结果调用DefaultIfEmpty方法来执行左外连接。

在实践中,最常见的情况是连接两个数据源。这是一个连接,只有在主键和外键之间存在连接时,辅助资源才会连接到主资源。主要来源保持不变

const result = Enumerable.from(orders)
.groupJoin(Enumerable.from(orderItems),
pk => pk.id,
fk => fk.orderId,
(left, right) => ({...left, right}))
.selectMany(m => m.right.defaultIfEmpty(),
(left, right) => ({...left, ...right}))
.toArray();
结果

可以封装成函数
export const LeftJoin = (source, inner, pk, fk, result)
=> Enumerable.from(source)
.groupJoin(Enumerable.from(inner),
s => pk(s),
i => fk(i),
(left, right) => ({left, right}))
.selectMany(m => m.right.defaultIfEmpty(),
(prev, right) => result(prev.left, right));
右外连接是第二个集合的每个元素所在的连接返回,不管它在第一个元素中是否有任何相关元素收集。方法来执行右外连接在组连接的结果上使用DefaultIfEmpty方法。

右连接与左连接完全相反。这是一个连接,只有当主键和外键之间存在链接时,主资源才会连接到辅助资源。二次源保持不变。

与leftJoin的情况一样,LINQ中没有rightJoin函数,因此我们将使用LINQ自己编写它。
Enumerable.prototype.rightJoin = function(inner, pk, fk, result) {
return RightJoin(this, inner, pk, fk, result);
}
结果如下
const result = Enumerable.from(orders)
.rightJoin(Enumerable.from(orderItems),
pk => pk.id,
fk => fk.orderId,
(left, right) => ({...left, ...right})
).toArray();

当左表 (table1) 或右表 (table2) 记录中有匹配项时,FULL OUTER JOIN 关键字将返回所有记录。

它基本上同时执行左连接和右连接。因此,将显示来自左集合和右集合的所有记录。同样,在LINQ中没有调用完全外部连接的等效组件,因此我们编写自己的组件。正如您将看到的,完整的外部连接将是我们已经创建的LeftJoin和RightJoin方法的组合。
export const FullOuterJoin = (source, inner, pk, fk, result) => {
var left = LeftJoin(source, inner, pk, fk, result);
var right = RightJoin(source, inner, pk, fk, result);
return left.unionDistinct(right);
}
我们将用fulllouterjoin方法扩展Enumerable
Enumerable.prototype.fullOuterJoin = function(inner, pk, fk, result) {
return FullOuterJoin(this, inner, pk, fk, result);
}

即使左侧的记录Id = 3在右侧没有相应的记录,右侧的记录Userld = 4在左侧没有相应的记录,它们仍然会在结果集合中。结果如下:
