查询性能降低:具有$ lookup和$ and / $ or的MongoDB

时间:2018-11-12 17:40:04

标签: javascript mongodb performance graphql graphql-tag

我试图找到一种方法来创建一种引擎,该引擎将GraphQL查询过滤器转换为MongoDB聚合,同时保持性能。我们的应用程序必须通过有时对集合B,C甚至D应用过滤器来限制集合A的结果。

为了更好地理解,这是有关如何将过滤器转换为MongoDB的示例。

此:

{
  "filter": {
    "return": null,
    "AND": [{
      "customer_WITH": {
        "OR": [{
          "code": "CUSTOMER NAME"
        }, {
          "commercialName_LIKE": "CUSTOMER NAME"
        }, {
          "corporateName_LIKE": "CUSTOMER NAME"
        }]
      }
    }],
    "OR": [{
      "dispatcher_WITH": {
        "company_WITH": {
          "corporateName_LIKE": "COMPANY NAME"
        }
      }
    }, {
      "redispatcher_WITH": {
        "company_WITH": {
          "corporateName_LIKE": "COMPANY NAME"
        }
      }
    }],
    "reversal": null
  }
}

被翻译为:

[{
  "$match": {
    "return": {
      "$eq": null
    },
    "reversal": {
      "$eq": null
    },
    "company": {
      "$eq": ObjectId("xxxxxxxxxxxxxxxxxxxxxxxx")
    }
  }
}, {
  "$lookup": {
    "as": "dispatcher",
    "from": "shippers",
    "localField": "dispatcher",
    "foreignField": "_id"
  }
}, {
  "$unwind": {
    "path": "$dispatcher",
    "preserveNullAndEmptyArrays": true
  }
}, {
  "$lookup": {
    "as": "dispatcher.company",
    "from": "companies",
    "localField": "dispatcher.company",
    "foreignField": "_id"
  }
}, {
  "$unwind": {
    "path": "$dispatcher.company",
    "preserveNullAndEmptyArrays": true
  }
}, {
  "$lookup": {
    "as": "redispatcher",
    "from": "shippers",
    "localField": "redispatcher",
    "foreignField": "_id"
  }
}, {
  "$unwind": {
    "path": "$redispatcher",
    "preserveNullAndEmptyArrays": true
  }
}, {
  "$lookup": {
    "as": "redispatcher.company",
    "from": "companies",
    "localField": "redispatcher.company",
    "foreignField": "_id"
  }
}, {
  "$unwind": {
    "path": "$redispatcher.company",
    "preserveNullAndEmptyArrays": true
  }
}, {
  "$lookup": {
    "as": "customer",
    "from": "customers",
    "localField": "customer",
    "foreignField": "_id"
  }
}, {
  "$match": {
    "$or": [{
      "dispatcher.company.corporateName": {
        "$regex": /\sCOMPANY\sNAME/
      }
    }, {
      "redispatcher.company.corporateName": {
        "$regex": /\sCOMPANY\sNAME/
      }
    }],
    "$and": [{
      "$or": [{
        "customer.code": {
          "$eq": "CUSTOMER NAME"
        }
      }, {
        "customer.commercialName": {
          "$regex": /CUSTOMER\sNAME/
        }
      }, {
        "customer.corporateName": {
          "$regex": /CUSTOMER\sNAME/
        }
      }]
    }]
  }
}, {
  "$unwind": {
    "path": "$customer",
    "preserveNullAndEmptyArrays": true
  }
}, {
  "$group": {
    "_id": "$invoiceNo",
    "__rootId": {
      "$first": "$_id"
    },
    "company": {
      "$first": "$company"
    },
    "customer": {
      "$first": "$customer._id"
    },
    "dispatcher": {
      "$first": "$dispatcher._id"
    },
    "redispatcher": {
      "$first": "$redispatcher._id"
    },
    "driverPlate": {
      "$first": "$driverPlate"
    },
    "key": {
      "$first": "$key"
    },
    "activities": {
      "$first": "$activities"
    },
    "serialNo": {
      "$first": "$serialNo"
    },
    "invoiceNo": {
      "$first": "$invoiceNo"
    },
    "incidents": {
      "$first": "$incidents"
    },
    "deliveries": {
      "$first": "$deliveries"
    },
    "return": {
      "$first": "$return"
    }
  }
}, {
  "$project": {
    "_id": "$__rootId",
    "company": "$company",
    "customer": "$customer",
    "dispatcher": "$dispatcher",
    "redispatcher": "$redispatcher",
    "driverPlate": "$driverPlate",
    "key": "$key",
    "activities": "$activities",
    "serialNo": "$serialNo",
    "invoiceNo": "$invoiceNo",
    "incidents": "$incidents",
    "deliveries": "$deliveries",
    "return": "$return"
  }
}, {
  "$sort": {
    "invoiceNo": -1
  }
}, {
  "$limit": 51
}]

引擎足够聪明,可以将不需要$ lookups的$ match属性重新分配到第一个位置,如果需要,则紧接在$ lookups之后,但是如果它们在$ and / $或condition块内,则它们是无论最后一个$ lookup之后的属性如何,都将重新分配。

我可以扫描$中使用的内容,并将其解构为新的重新分配的$ match阶段,但是我需要弄清楚如何处理$ or运算符:我无法在其上应用相同的解构思想会使条件无效。

所以我的问题是:是否有另一种方法可以将阶段$ lookup与$ and / $ or一起使用并大幅提高性能?

创建更多索引将无济于事,因为它们没有用于$ lookup。正如MongoDB团队建议的那样,提高$ match阶段也是不可能的,因为这会破坏条件。所以我现在没主意了。

最诚挚的问候。

0 个答案:

没有答案