gpt4 book ai didi

javascript - 如何比较数组并计算匹配项

转载 作者:行者123 更新时间:2023-11-30 20:34:41 24 4
gpt4 key购买 nike

我有一个包含以下文档的集合:

 {
_id: ObjectId("000000000000000000059734"),
locations: ["A", "B", "C"]
},

{
_id: ObjectId("000000000000000000059735"),
locations: ["A", "D", "K"]
},

{
_id: ObjectId("000000000000000000059736"),
locations: ["1", "3", "C"]
}

现在我想要的是根据以下数组项计算文档总数:

let array = ['A', 'B', '1'];

我想要的结果是:

{
'A': 2,
'B': 1,
'1': 1
}

我尝试过的:

db.getCollection('mycollection').aggregate([
{$group: {
"_id": {
"location": {
"A": { "$sum": { "$cond": [{ "$in": [ "A", "$locations" ] },1,0] } },
"B": { "$sum": { "$cond": [{ "$in": [ "B", "$locations" ] },1,0] } },
"1": { "$sum": { "$cond": [{ "$in": [ "1", "$locations" ] },1,0] } },
}
}
}}
])

但是我的查询结果格式和我想要的不一样。

感谢任何帮助和指导。

最佳答案

如果你至少有 MongoDB 3.4.4,那么你可以这样做:

var array = ['A', 'B', '1'];

db.getCollection('mycollection').aggregate([
{ "$project": {
"locations": {
"$map": {
"input": {
"$filter": {
"input": "$locations",
"cond": { "$in": [ "$$this", array ] }
}
},
"in": { "k": "$$this", "v": 1 }
}
}
}},
{ "$unwind": "$locations" },
{ "$group": {
"_id": "$locations.k",
"v": { "$sum": "$locations.v" }
}},
{ "$sort": { "_id": 1 } },
{ "$group": {
"_id": null,
"obj": { "$push": { "k": "$_id", "v": "$v" } }
}},
{ "$replaceRoot": {
"newRoot": { "$arrayToObject": "$obj" }
}}
])

对于没有类似 $arrayToObject 的旧版本,您将在从服务器返回结果“之后”转换结果,如下所示:

var array = ['A', 'B', '1'];

db.getCollection('mycollection').aggregate([
{ "$project": {
"locations": {
"$map": {
"input": {
"$filter": {
"input": "$locations",
"cond": {
// "$in": [ "$$this", array ]
"$or": array.map(a => ({ "$eq": [ "$$this", a ] }) )
}
}
},
"in": { "k": "$$this", "v": 1 }
}
}
}},
{ "$unwind": "$locations" },
{ "$group": {
"_id": "$locations.k",
"v": { "$sum": "$locations.v" }
}},
{ "$sort": { "_id": 1 } },
{ "$group": {
"_id": null,
"obj": { "$push": { "k": "$_id", "v": "$v" } }
}},
/*
{ "$replaceRoot": {
"newRoot": { "$arrayToObject": "$obj" }
}}
*/
]).map(d =>
d.obj.reduce((acc,curr) => Object.assign(acc,{ [curr.k]: curr.v }),{})
)

无论哪种情况,第一步都是到 $project$map为了查看文档数组中的每个值并将其与比较数组进行比较。事实上我们使用 $filter只返回“匹配项”和 $map返回值 1 以计算每次出现的次数。

“过滤”有两种基本方法,要么使用 $in对于支持运算符的版本,或使用 $or在引入之前的旧版本中。

坦率地说,可以简单地使用 $setIntersection只要您的文档数据是“唯一的”,就可以获得匹配项,因为没有文档数组包含多次出现的值。所以我在这里玩安全游戏 $filter因为我不知道你的数据。选择任何花色。

 // If the "locations" content is meant to be "unique"
{ "$project": {
"locations": {
"$map": {
"input": {
"$setIntersection": [ "$locations", array ]
},
"in": { "k": "$$this", "v": 1 }
}
}
}},

注意 $mapkv 属性形式输出。这将作为一种模式继续贯穿管道的其余部分。

因为您想“聚合”数组项中的 k 值,所以我们使用 $unwind所以我们可以跨文档将它们加在一起。然后将其输入 $groupk 的值上并使用 $sum在每个 v 上有效地“计算”出现次数。

$sort是完全可选的,实际上您不应该关心单个输出文档中键的顺序。请注意与您的“期望”的区别,但这只是一个明显的事实,即 “1” 在词汇上“小于”“A”。所以你无法抗拒它,这就是世界运转的方式。

下一阶段就是$group到单个文档。在这里,我们继续重构为包含 kv 的对象的“数组”。

之所以这样,是因为最后的处理。无论你有一个带有 $arrayToObject 的 MongoDB支持(实际上从 3.4.4 开始就包含了,尽管文档声称是 3.6)。在你这样做的地方,我们只是在 $replaceRoot 中提供生成的“数组”作为输入阶段以返回最终输出。

如果您没有该功能,您可以处理游标结果(此处使用 shell Cursor.map() 显示)并在进一步处理之前转换文档。任何迭代器方法都可以,而且大多数驱动程序都有一个 Cursor.map() .在这里并不是那么重要,因为在这种情况下聚合管道会生成一个文档。

在现代 shell 版本中工作的 JavaScript 方式是简单地应用 .reduce()在数组上并将输出对象转换为所需的对象输出。它基本上与服务器执行的操作完全相同,但只是在客户端代码中。

两种形式都返回所需的结果:

{
"1" : 1.0,
"A" : 2.0,
"B" : 1.0
}

关于javascript - 如何比较数组并计算匹配项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49964519/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com