简体   繁体   English

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

[英]Ignore $in if empty array is provided

I have the following model:我有以下 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']>;
};

Note: interface matches the model exactly but i pasted this as its much shorter.注意:接口与 model 完全匹配,但我将其粘贴为它更短。

I am using the following data to filter through this collection:我正在使用以下数据过滤此集合:

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

What i want to achieve is to find every document and check if the corresponding array has at least one of the values from the array i sent via includeFilters.我想要实现的是找到每个文档并检查相应的数组是否具有我通过 includeFilters 发送的数组中的至少一个值。 While it has none of the values sent via excludeFilters.虽然它没有通过 excludeFilters 发送的值。

To do this i used the following query:为此,我使用了以下查询:

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 }
      );

This seems to works fine as long as all of the arrays in includeFilters array have at least one value.只要includeFilters 数组中的所有 arrays 至少有一个值,这似乎就可以正常工作。 But if an empty array is provided then no matches are found with $in, from what i understand $in requires at least one value to be present, but as nothing is provided then nothing is found.但是,如果提供了一个空数组,那么在 $in 中找不到匹配项,据我所知,$in 要求至少存在一个值,但由于没有提供任何内容,因此什么也找不到。 On the other hand, $nin works fine (at least i'd like to think so) because its not trying to exclude any values.另一方面, $nin工作正常(至少我想这样认为),因为它没有试图排除任何值。

What i would like to achieve is that if an empty array is provided to $in then it outright just skips through that filter and doesnt look at it.我想要实现的是,如果向 $in 提供了一个空数组,那么它会直接跳过该过滤器并且不查看它。 When doing this in mysql if an empty array is provided then its ignored and every record is returned as a result.在 mysql 中执行此操作时,如果提供了一个空数组,则其将被忽略并返回每条记录作为结果。 This is what i want with mongodb.这就是我想要的 mongodb。

What i have tried till now are a couple of things.到目前为止,我尝试过的是几件事。

First i tried to just add every possible value to array's that are empty, this did not work for one reason, not all documents have the tags,genres and demographic data.首先,我尝试将所有可能的值添加到空数组中,这不起作用,原因之一是,并非所有文档都有标签、流派和人口统计数据。 So in the end nearly 90% of all documents are not included in the result.所以最终将近 90% 的文档没有包含在结果中。

Second thing i tried was to enable the ignoreUndefined option in the connection options.我尝试的第二件事是在连接选项中启用ignoreUndefined选项。 And then when creating the query check if the length is 0, if it is, pass undefined to $in .然后在创建查询时检查长度是否为 0,如果是,则将 undefined 传递给$in This did not work.这没有用。

Third thing i tried was going through every possible scenario where some array is empty, this was bad for obvious reasons so i scratched it.我尝试的第三件事是遍历所有可能的情况,其中某个数组为空,由于显而易见的原因,这很糟糕,所以我抓了它。

Fourth thing i tried was to make a function to build a dynamic query of sorts, this also became very messy because of the amount of possibilities.我尝试的第四件事是制作一个 function 来构建各种动态查询,由于可能性的数量,这也变得非常混乱。

Fifth and last thing i tried was using $or with the idea that the empty results would somehow be skipped.我尝试的第五件事也是最后一件事是使用$or并认为会以某种方式跳过空结果。

The easiest solution is to just dynamically create the whole filter.最简单的解决方案是动态创建整个过滤器。 It will also simplify your query.它还将简化您的查询。 You can do it like this:你可以这样做:

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 });

Here is a snippet for testing:这是一个用于测试的片段:

 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)

To make this work better with TypeScript you could use Nenad's approach with ES6 methods为了使 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.

相关问题 删除或忽略数组中的空单元格 - Remove or ignore empty cells in array 如何忽略空数组元素进行长度计算 - How ignore empty array elements for length calculation Firebase错误:提供给sendToDevice()的注册令牌必须是非空字符串或非空数组 - Firebase Error: Registration token(s) provided to sendToDevice() must be a non-empty string or a non-empty array 检查重复项时如何忽略数组中的空值-Javascript - How to ignore empty values in array when checking for duplicates - Javascript 仅对定义的参数过滤数组。 忽略空参数 - Only filter Array for the defined parameters. ignore empty parameters 忽略/删除 null,数组计数中未定义和空值 - Javascript - Ignore/Remove null, undefined and empty values in array count - Javascript Firebase Cloud Function错误:提供给sendToDevice()的注册令牌必须是非空字符串或非空数组 - Firebase Cloud Function error: Registration token(s) provided to sendToDevice() must be a non-empty string or a non-empty array 如果值为空则忽略键 - Ignore key if empty value 忽略空 object - Ignore empty object 为什么 Array.prototype.map 会忽略稀疏数组中的空槽,而 Array.prototype.join 不会? - Why does Array.prototype.map ignore empty slots in a sparse array whereas Array.prototype.join does not?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM