我正在寻找一个充当$setIsSubset
的查询,但不考虑重复值。
例如,[1,1,2,3]
是[1,2,3,4]
的子集,因为集合没有重复的值。
如何编写查询,使[1,1,2,3]
不是[1,2,3,4]
的子集?
预期输出示例:
INPUT | TARGET | RESULT
[1] [1,2,3,4] TRUE
[1,2,3] [1,2,3,4] TRUE
[1,1,2,3] [1,2,3,4] FALSE
[1,2,3,4] [1,2,3,4] TRUE
[1,3] [1,2,3,4] TRUE
[1,11,5] [1,2,3,4] FALSE
[1,2,2,3] [1,2,3,4] FALSE
答案 0 :(得分:2)
我建议不要在mongo查询中进行如此繁琐的处理,因为您可以使用任何编程语言轻松地完成相同的任务。但是,如果您仍需要mongo,则只要对输入数组和目标数组都进行了排序,以下查询可以为您提供预期的输出。
db.collection.aggregate([
{
$project:{
"modifiedInput":{
$reduce:{
"input":"$input",
"initialValue":{
"data":[],
"postfix":0,
"index":0,
"nextElem":{
$arrayElemAt:["$input",1]
}
},
"in":{
"data":{
$concatArrays:[
"$$value.data",
[
{
$concat:[
{
$toString:"$$this"
},
"-",
{
$toString:"$$value.postfix"
}
]
}
]
]
},
"postfix":{
$cond:[
{
$eq:["$$this","$$value.nextElem"]
},
{
$sum:["$$value.postfix",1]
},
0
]
},
"nextElem": {
$arrayElemAt:["$input", { $sum : [ "$$value.index", 2] }]
},
"index":{
$sum:["$$value.index",1]
}
}
}
},
"modifiedTarget":{
$reduce:{
"input":"$target",
"initialValue":{
"data":[],
"postfix":0,
"index":0,
"nextElem":{
$arrayElemAt:["$target",1]
}
},
"in":{
"data":{
$concatArrays:[
"$$value.data",
[
{
$concat:[
{
$toString:"$$this"
},
"-",
{
$toString:"$$value.postfix"
}
]
}
]
]
},
"postfix":{
$cond:[
{
$eq:["$$this","$$value.nextElem"]
},
{
$sum:["$$value.postfix",1]
},
0
]
},
"nextElem": {
$arrayElemAt:["$target", { $sum : [ "$$value.index", 2] }]
},
"index":{
$sum:["$$value.index",1]
}
}
}
}
}
},
{
$project:{
"_id":0,
"matched":{
$eq:[
{
$size:{
$setDifference:["$modifiedInput.data","$modifiedTarget.data"]
}
},
0
]
}
}
}
]).pretty()
数据集:
{
"_id" : ObjectId("5d6e005db674d5c90f46d355"),
"input" : [
1
],
"target" : [
1,
2,
3,
4
]
}
{
"_id" : ObjectId("5d6e005db674d5c90f46d356"),
"input" : [
1,
2,
3
],
"target" : [
1,
2,
3,
4
]
}
{
"_id" : ObjectId("5d6e005db674d5c90f46d357"),
"input" : [
1,
1,
2,
3
],
"target" : [
1,
2,
3,
4
]
}
{
"_id" : ObjectId("5d6e005db674d5c90f46d358"),
"input" : [
1,
2,
3,
4
],
"target" : [
1,
2,
3,
4
]
}
{
"_id" : ObjectId("5d6e005db674d5c90f46d359"),
"input" : [
1,
3
],
"target" : [
1,
2,
3,
4
]
}
{
"_id" : ObjectId("5d6e005db674d5c90f46d35a"),
"input" : [
1,
5,
11
],
"target" : [
1,
2,
3,
4
]
}
{
"_id" : ObjectId("5d6e005db674d5c90f46d35b"),
"input" : [
1,
2,
2,
3
],
"target" : [
1,
2,
3,
4
]
}
输出:
{ "matched" : true }
{ "matched" : true }
{ "matched" : false }
{ "matched" : true }
{ "matched" : true }
{ "matched" : false }
{ "matched" : false }
说明::为避免消除相同的值,我们为每个值添加了后缀计数器。例如,[1,1,1,2,3,3,4,4]将变为[“ 1-0”,“ 1-1”,“ 1-2”,“ 2-0”,“ 3- 0“,” 3-1“,” 4-0“,” 4-1“,” 4-2“]]。输入和目标数组转换后,将计算出设置的差。如果设置差异的大小为零,那就是匹配。
答案 1 :(得分:1)
您可以尝试以下汇总:
let input = [1,2,3];
let inputSize = 3;
db.collection.aggregate([
{
$project: {
uniqueTarget: { $setUnion: [ "$target" ] }
}
},
{
$addFields: {
filtered: {
$reduce: {
input: input,
initialValue: "$uniqueTarget",
in: {
$filter: {
input: "$$value",
as: "current",
cond: { $ne: [ "$$this", "$$current" ] }
}
}
}
}
}
},
{
$project: {
result: {
$eq: [
{ $size: "$filtered" },
{ $subtract: [ { $size: "$uniqueTarget" }, inputSize ] }
]
}
}
}
])
它以$setUnion开头,以确保target
数组中没有重复项。然后,您可以运行$reduce遍历input
并从目标中删除当前处理的元素。每次迭代都应删除单个元素,以使filtered
的{{3}}等于uniqueTarget
-inputSize
的{{3}}