繁体   English   中英

如果提供了空数组,则忽略 $in

[英]Ignore $in if empty array is provided

我有以下 model:

export type IMangaModel = Document & {
  _id: string;
  title: string;
  description: string;
  demographic: Array<string>;
  genre: Array<string>;
  tags: Array<string>;
  related: Array<IMangaModel>;
  cover_image: {
    extraLarge: string | null;
    large: string | null;
    medium: string | null;
  };
  banner: string | null;
  al_id: number;
  al_url: string;
  likes: Array<IUserModel['_id']>;
};

注意:接口与 model 完全匹配,但我将其粘贴为它更短。

我正在使用以下数据过滤此集合:

includeFilters: {
    genres: Array<string>;
    tags: Array<string>;
    demographics: Array<string>;
  };
  excludeFilters: {
    genres: Array<string>;
    tags: Array<string>;
    demographics: Array<string>;
  };

我想要实现的是找到每个文档并检查相应的数组是否具有我通过 includeFilters 发送的数组中的至少一个值。 虽然它没有通过 excludeFilters 发送的值。

为此,我使用了以下查询:

const results = await this._manga
      .find(
        {
          tags: {
            $elemMatch: {
              $in: data.includeFilters.tags,
              $nin: data.excludeFilters.tags,
            },
          },
          genre: {
            $elemMatch: {
              $in: data.includeFilters.genres,
              $nin: data.excludeFilters.genres,
            },
          },
          demographic: {
            $elemMatch: {
              $in: data.includeFilters.demographics,
              $nin: data.excludeFilters.demographics,
            },
          },
        },
        { al_id: 1 }
      );

只要includeFilters 数组中的所有 arrays 至少有一个值,这似乎就可以正常工作。 但是,如果提供了一个空数组,那么在 $in 中找不到匹配项,据我所知,$in 要求至少存在一个值,但由于没有提供任何内容,因此什么也找不到。 另一方面, $nin工作正常(至少我想这样认为),因为它没有试图排除任何值。

我想要实现的是,如果向 $in 提供了一个空数组,那么它会直接跳过该过滤器并且不查看它。 在 mysql 中执行此操作时,如果提供了一个空数组,则其将被忽略并返回每条记录作为结果。 这就是我想要的 mongodb。

到目前为止,我尝试过的是几件事。

首先,我尝试将所有可能的值添加到空数组中,这不起作用,原因之一是,并非所有文档都有标签、流派和人口统计数据。 所以最终将近 90% 的文档没有包含在结果中。

我尝试的第二件事是在连接选项中启用ignoreUndefined选项。 然后在创建查询时检查长度是否为 0,如果是,则将 undefined 传递给$in 这没有用。

我尝试的第三件事是遍历所有可能的情况,其中某个数组为空,由于显而易见的原因,这很糟糕,所以我抓了它。

我尝试的第四件事是制作一个 function 来构建各种动态查询,由于可能性的数量,这也变得非常混乱。

我尝试的第五件事也是最后一件事是使用$or并认为会以某种方式跳过空结果。

最简单的解决方案是动态创建整个过滤器。 它还将简化您的查询。 你可以这样做:

let elem_match = {
  tags: {},
  genres: {},
  demographics: {}
}

for (let key in data.includeFilters){
  if(data.includeFilters[key].length) elem_match[key]["$in"] = data.includeFilters[key];
}

for (let key in data.excludeFilters){
  if(data.excludeFilters[key].length) elem_match[key]["$nin"] = data.excludeFilters[key];
}

let filter = {};
for (let key in elem_match){
  if(Object.keys(elem_match[key]).length !== 0) filter[key] = { $elemMatch: elem_match[key]}
}

const results = await this._manga.find(filter, { al_id: 1 });

这是一个用于测试的片段:

 let includeFilters = { genres: ['1', '2'], tags: ['1', '2'], demographics: ['1', '2'] }; let excludeFilters = { genres: ['1', '2'], tags: ['1', '2'], demographics: ['1', '2'] }; let elem_match = { tags: {}, genres: {}, demographics: {} } for (let key in includeFilters) { if(includeFilters[key].length) elem_match[key]["$in"] = includeFilters[key]; } for (let key in excludeFilters) { if(excludeFilters[key].length) elem_match[key]["$nin"] = excludeFilters[key]; } let filter = {}; for (let key in elem_match) { if(Object.keys(elem_match[key]).length:== 0) filter[key] = { $elemMatch. elem_match[key]} } console:log('Filter, ', filter)

为了使 TypeScript 更好地工作,您可以将 Nenad 的方法与 ES6 方法一起使用

const filters = Object.fromEntries(
  Object.entries(body).flatMap(([filterType, filters]) =>
    Object.entries(filters)
      .filter(([, values]) => values.length)
      .map(([key, value]) =>
        filterType === "includeFilters"
          ? [key, { $elemMatch: { $in: [...value] } }]
          : [key, { $elemMatch: { $nin: [...value] } }]
      )
  )
);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM