如何计算包含数组中值的文档?

Posted

技术标签:

【中文标题】如何计算包含数组中值的文档?【英文标题】:How do I count the documents that include a value within an array? 【发布时间】:2021-01-03 10:56:52 【问题描述】:

我有一个 Mongoose abTest 文档,它有两个字段:

    status。这是一个字符串枚举,类型可以是activeinactivedraftvalidCountryCodes。这是一个字符串枚举数组(GBEUAU 等)。默认为空。

在数据库中,在任何时候,我只希望每个validCountryCode 有一个活动的abTest,因此我在创建或编辑新的abTest 之前执行一些验证。

为此,我编写了一个函数来尝试计算具有statusactive 和包含countryCodes 之一的文档的数量。

如果计数大于一,该函数将返回。如果是这样,我会抛出一个验证错误。

if (params.status === 'active') 
  const activeTestForCountryExists = await checkIfActiveAbTestForCountry(
    validCountryCodes,
  );
  if (params.activeTestForCountryExists) 
    throw new ValidationError(
      message: 'There can only be one active test for each country code.',
    );
  


const abTest = await AbTest.create(params);

checkIfActiveAbTestForCountry() 看起来像这样:

const checkIfActiveAbTestForCountry = async countryCodes => 
  const query = 
    status: 'active',
  ;

  if (
    !countryCodes ||
    (Array.isArray(countryCodes) && countryCodes.length === 0)
  ) 
    query.validCountryCodes = 
      $eq: [],
    ;
   else 
    query.validCountryCodes =  $in: [countryCodes] ;
  

  const count = await AbTest.countDocuments(query);
  return count > 0;
;

count 查询不仅应该计算完全匹配的数组,还应该计算任何部分匹配。

如果在 DB 中有一个 active abTest 和一个 validCountryCodes 数组 ['GB', 'AU',],则尝试使用 ['GB' 创建一个新的 abTest 应该会失败。因为已经有一个使用GB 作为validCountryCode 的测试。

同样,如果有一个带有validCountryCodes 数组['AU'] 的测试,那么创建一个带有['AU,'NZ']validCountryCodes 的测试也应该失败。

目前都没有强制执行。

我该怎么做?这可以写一个查询来检查吗?

我考虑过迭代 params.validCountryCodes 并计算包含每个文档的文档,但这似乎是一种不好的做法。

【问题讨论】:

【参考方案1】:

看看这个 MongoDB documantation。

据我了解,您需要找出是否有任何文档至少包含指定的countryCodes 之一并且它具有active 状态。那么您的查询应该如下所示:

 
  status: 'active',
  $or: [
     validCountryCodes: countryCodes[0] ,
     validCountryCodes: countryCodes[1] ,
    // ...
  ]

请注意,计数文档并不是检查文档是否存在的有效方式,而是使用 findOne 并仅投影一个字段。

【讨论】:

如果我这样做,那么带有validCountryCodes['AU','GB'] 的文档将与['GB'] 不匹配。应该! 如果您有这样的文档:status: 'active', validCountryCodes: ['AU','GB'] 它将匹配此查询 status: 'active', validCountryCodes: 'GB' ` 真的!但是通过checkIfActiveAbTestForCountry 传入的参数是countryCodes 的数组,所以我本质上是在计算至少有一个共同元素的文档 @judgejab 我已经更新了答案,你可以使用循环来构建$or 数组【参考方案2】:

您正在使用正确的 mongo-query 来满足您的要求。您能否验证从您的应用程序执行的实际查询是否相同?检查here

 status: 'active', validCountryCodes:  $in: [ countryCodes ]  

例如;以下查询:

 status: 'active', validCountryCodes:  $in: ['GB' ]  

应该匹配文档:

 status: 'active', validCountryCodes: ['AU','GB'] 

【讨论】:

以上是关于如何计算包含数组中值的文档?的主要内容,如果未能解决你的问题,请参考以下文章

用中值替换numpy数组中的零

如何更改 numpy 数组中值的位置?

java怎样判断一个数组中值的唯一性

如何保留数组中值的引号

如何仅查看猫鼬中值的第一个字母来查找所有文档

如何计算 SQLite 中值的中位数?