如何在 MongoDB V4.4 中绕过其每个管道的 $facet 内存 100MB 内存限制?
How to bypass $facet memory 100MB memory limit on each of its pipeline in MongoDB V4.4?
我正在使用 MongoDB 3.4,最近在 Beta 环境中将其升级到 4.4。我有一个使用 facet 的查询,它超出了 100MB 的大小限制 issue.I 看到 Jira link 在这里解释了这个问题:https://jira.mongodb.org/browse/SERVER-40317
查询是根据用户输入动态生成的,因此很难直接对查询进行更改我认为这是最后的手段。
无论如何我都在寻找绕过这个限制的方法。 AllowDiskUsage 也不起作用,如上文所述 link.
你必须像这样使用 mongoose utils allowdiskusage:
return OrderEntity
.aggregate(compendiumAggregation(query))
.allowDiskUse(true)
.then(success(res))
.catch(next);
已确认这可以解决问题:
db.adminCommand({setParameter: 1, internalQueryFacetMaxOutputDocSizeBytes: 335544320})
使用上述命令影响的 RAM 限制从默认的 100MB 更改为 320MB
查看更改是否到位:
use admin
db.runCommand( { getParameter : 1, “internalQueryFacetMaxOutputDocSizeBytes” : 1 } )
此更改是临时的,要使其永久化,您需要添加到 mongodb.conf 文件以在启动时生效:
setParameter:
internalQueryFacetMaxOutputDocSizeBytes: 335544320
与您的问题不完全相关,但您的聚合管道看起来有点傻。你到底为什么要用所有这些 $and
/ $or
只有一个参数?
如果我没记错的话,你的聚合管道是这样的:
responses.aggregate([
{
'$match': {
surId: '5f548bda279ef41b7a9cd23c',
preview: 0,
resStatus: '1',
archive: { '$exists': false },
modified: {
'$gte': ISODate('2020-08-31T20:59:59.999Z'),
'$lt': ISODate('2020-11-30T21:00:00.000Z')
},
'resAObj.601aaf29fd93f74cab932141': { $in: [Object] }
}
},
{ $project: { 'resAObj.601aaf29fd93f74cab932141': 1, surId: 1 },
{
'$facet': {
'0': [
{ '$match': { 'resAObj.601aaf29fd93f74cab932141': { '$elemMatch': [Object] } } },
{ '$addFields': { 'resAObj.601aaf29fd93f74cab932141': { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'item', cond: { '$and': [Array] } } } } },
{
'$project': {
surId: '$surId',
d_DMID7235_0_d: { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'dmi_0', cond: { '$eq': [Array] } } },
d_DMID7237_0_d: { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'dmi_0', cond: { '$eq': [Array] } } },
d_DMID7239_0_d: { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'dmi_0', cond: { '$eq': [Array] } } },
d_DMID7240_0_d: { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'dmi_0', cond: { '$eq': [Array] } } },
d_DMID7241_0_d: { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'dmi_0', cond: { '$eq': [Array] } } },
d_DMID7242_0_d: { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'dmi_0', cond: { '$eq': [Array] } } },
d_DMID7243_0_d: { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'dmi_0', cond: { '$eq': [Array] } } },
d_DMID7244_0_d: { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'dmi_0', cond: { '$eq': [Array] } } },
d_DMID7245_0_d: { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'dmi_0', cond: { '$eq': [Array] } } },
index: '0'
}
},
{
'$project': {
surId: '$surId',
DMID7235: { '$ifNull': ['$d_DMID7235_0_d', 0] },
DMID7237: { '$ifNull': ['$d_DMID7237_0_d', 0] },
DMID7239: { '$ifNull': ['$d_DMID7239_0_d', 0] },
DMID7240: { '$ifNull': ['$d_DMID7240_0_d', 0] },
DMID7241: { '$ifNull': ['$d_DMID7241_0_d', 0] },
DMID7242: { '$ifNull': ['$d_DMID7242_0_d', 0] },
DMID7243: { '$ifNull': ['$d_DMID7243_0_d', 0] },
DMID7244: { '$ifNull': ['$d_DMID7244_0_d', 0] },
DMID7245: { '$ifNull': ['$d_DMID7245_0_d', 0] },
index: '0'
}
}
],
'1': ['... same as above'],
'2': ['... same as above'],
'3': ['... same as above'],
'4': ['... same as above'],
'5': ['... same as above'],
'6': ['... same as above'],
'7': ['... same as above'],
total: [{ '$count': 'total' }],
baseValue: ['... same as above']
}
},
{ '$project': { mergedArray: { '$concatArrays': ['[=10=]', '', '', '', '', '', '', '', '$total', '$baseValue'] } } },
{ '$unwind': '$mergedArray' },
{ '$replaceRoot': { newRoot: '$mergedArray' } }
])
你所有的操作都基于一个字段resAObj.601aaf29fd93f74cab932141
,这看起来很奇怪。也许纯 javascript 代码可以更好地解决它。
您可以使用 $map, $arrayToObject and $objectToArray。实际上我根本看不出使用 $facet
的原因。
没有样本输入数据和样本结果很难给出答案,但我认为聚合管道可以写得更简单。
我正在使用 MongoDB 3.4,最近在 Beta 环境中将其升级到 4.4。我有一个使用 facet 的查询,它超出了 100MB 的大小限制 issue.I 看到 Jira link 在这里解释了这个问题:https://jira.mongodb.org/browse/SERVER-40317
查询是根据用户输入动态生成的,因此很难直接对查询进行更改我认为这是最后的手段。
无论如何我都在寻找绕过这个限制的方法。 AllowDiskUsage 也不起作用,如上文所述 link.
你必须像这样使用 mongoose utils allowdiskusage:
return OrderEntity
.aggregate(compendiumAggregation(query))
.allowDiskUse(true)
.then(success(res))
.catch(next);
已确认这可以解决问题:
db.adminCommand({setParameter: 1, internalQueryFacetMaxOutputDocSizeBytes: 335544320})
使用上述命令影响的 RAM 限制从默认的 100MB 更改为 320MB
查看更改是否到位:
use admin
db.runCommand( { getParameter : 1, “internalQueryFacetMaxOutputDocSizeBytes” : 1 } )
此更改是临时的,要使其永久化,您需要添加到 mongodb.conf 文件以在启动时生效:
setParameter:
internalQueryFacetMaxOutputDocSizeBytes: 335544320
与您的问题不完全相关,但您的聚合管道看起来有点傻。你到底为什么要用所有这些 $and
/ $or
只有一个参数?
如果我没记错的话,你的聚合管道是这样的:
responses.aggregate([
{
'$match': {
surId: '5f548bda279ef41b7a9cd23c',
preview: 0,
resStatus: '1',
archive: { '$exists': false },
modified: {
'$gte': ISODate('2020-08-31T20:59:59.999Z'),
'$lt': ISODate('2020-11-30T21:00:00.000Z')
},
'resAObj.601aaf29fd93f74cab932141': { $in: [Object] }
}
},
{ $project: { 'resAObj.601aaf29fd93f74cab932141': 1, surId: 1 },
{
'$facet': {
'0': [
{ '$match': { 'resAObj.601aaf29fd93f74cab932141': { '$elemMatch': [Object] } } },
{ '$addFields': { 'resAObj.601aaf29fd93f74cab932141': { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'item', cond: { '$and': [Array] } } } } },
{
'$project': {
surId: '$surId',
d_DMID7235_0_d: { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'dmi_0', cond: { '$eq': [Array] } } },
d_DMID7237_0_d: { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'dmi_0', cond: { '$eq': [Array] } } },
d_DMID7239_0_d: { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'dmi_0', cond: { '$eq': [Array] } } },
d_DMID7240_0_d: { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'dmi_0', cond: { '$eq': [Array] } } },
d_DMID7241_0_d: { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'dmi_0', cond: { '$eq': [Array] } } },
d_DMID7242_0_d: { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'dmi_0', cond: { '$eq': [Array] } } },
d_DMID7243_0_d: { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'dmi_0', cond: { '$eq': [Array] } } },
d_DMID7244_0_d: { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'dmi_0', cond: { '$eq': [Array] } } },
d_DMID7245_0_d: { '$filter': { input: '$resAObj.601aaf29fd93f74cab932141', as: 'dmi_0', cond: { '$eq': [Array] } } },
index: '0'
}
},
{
'$project': {
surId: '$surId',
DMID7235: { '$ifNull': ['$d_DMID7235_0_d', 0] },
DMID7237: { '$ifNull': ['$d_DMID7237_0_d', 0] },
DMID7239: { '$ifNull': ['$d_DMID7239_0_d', 0] },
DMID7240: { '$ifNull': ['$d_DMID7240_0_d', 0] },
DMID7241: { '$ifNull': ['$d_DMID7241_0_d', 0] },
DMID7242: { '$ifNull': ['$d_DMID7242_0_d', 0] },
DMID7243: { '$ifNull': ['$d_DMID7243_0_d', 0] },
DMID7244: { '$ifNull': ['$d_DMID7244_0_d', 0] },
DMID7245: { '$ifNull': ['$d_DMID7245_0_d', 0] },
index: '0'
}
}
],
'1': ['... same as above'],
'2': ['... same as above'],
'3': ['... same as above'],
'4': ['... same as above'],
'5': ['... same as above'],
'6': ['... same as above'],
'7': ['... same as above'],
total: [{ '$count': 'total' }],
baseValue: ['... same as above']
}
},
{ '$project': { mergedArray: { '$concatArrays': ['[=10=]', '', '', '', '', '', '', '', '$total', '$baseValue'] } } },
{ '$unwind': '$mergedArray' },
{ '$replaceRoot': { newRoot: '$mergedArray' } }
])
你所有的操作都基于一个字段resAObj.601aaf29fd93f74cab932141
,这看起来很奇怪。也许纯 javascript 代码可以更好地解决它。
您可以使用 $map, $arrayToObject and $objectToArray。实际上我根本看不出使用 $facet
的原因。
没有样本输入数据和样本结果很难给出答案,但我认为聚合管道可以写得更简单。