MongoDB聚合,使用Node.js生成动态的AND和OR查询。

3

我在我的nodejs代码中使用MongoDB聚合查询遇到了问题。

const query = {
  '$expr':{
    '$and':[
      {'$eq': ['$appId', req.user.appId]},
    ]
  }
}

从前端接收到一个筛选对象,如下所示:

{
  shops: '604c776763c302032e610347',
  offset: '0',
  limit: '20',
}

我需要在查询中动态推送商店ID。需要是 appId -> user.appID AND targetFrom || targetTo <- 商店(来自过滤器对象的

商店可以是一个ID一组ID,为此我使用了$in运算符。

query['$expr']['$and'].push({
  $eq: [
    {
      $or: [
        {"targetFrom": {$in: bb}},
        {"targetTo": {$in: bb}}
      ]
    }
  ]
})

旧版本的代码如下:

const query = {
  $and: [
    {appId: req.user.appId}
  ]
}

query['$and'].push({
  $or: [
    {"targetFrom": {$in: bb}}, <- in bb is mongodb objectID
    {"targetTo": {$in: bb}}
  ]
})

更新

如何在我的对象数组items中通过ID搜索某个item

if(req.query.products) {
  typeof req.query.products === 'string' ? req.query.products = [req.query.products] : req.query.products
  let bb = req.query.products.map(function(el) { return mongoose.Types.ObjectId(el) })
  query['$expr']['$and'].push({
    $and: [
      {
        items: {
          $in: ['item.itemId', bb]
        }
       }
     ]
   })
}
1个回答

3
请看以下是否符合您的要求:
请查看以下链接:Mongoplayground 链接
假设如下:
  1. req.user.appId 是一个字符串。
  2. bb 是一个由对象ID或字符串组成的数组(例如: [ObjectId("asdfsd"),ObjectId("badsfds")]
const query = {
  "$expr": {
      $and: [{
        "$eq": ["$appId",req.user.appId],
      }]
      
  }
}

query['$expr']['$and'].push({
  $or: [
    {
      $in: [
        "$targetFrom",
        bb
      ]
    },
    {
      $in: [
        "$targetTo",
        bb
      ]
    }
  ]
})

编辑:更新要求:获取特定 appId 的所有对象,其中 targetFromtargetTo 为给定数组之一,而且 date 在给定的 startDateendDate 之间:

Monogplayground

在上面的 mongoplayground 中,我正在获取所有 appId 为 "1",startDate2022-01-01endDate2022-01-31,bb 为 ["a", "c", "x"] 的对象。这应该会获取所有3个文档,但是由于第三个文档中的 date2021-12-24,因此日期过滤器将其过滤掉。如果您在那之前更改日期,您将获得全部3个。

const query = {
  "$expr": {
      $and: [{
        "$eq": ["$appId",req.user.appId],
      }]

  }
}

query['$expr']['$and'] = query['$expr']['$and'].concat([{
          $and: [
            {
              $gte: [
                "$date",
                startDate
              ]
            },
            {
              $lt: [
                "$date",
                endDate
              ]
            }
          ]
        },{
  $or: [
    {
      $in: [
        "$targetFrom",
        bb
      ]
    },
    {
      $in: [
        "$targetTo",
        bb
      ]
    }
  ]
}])

编辑:需求已更新:需要添加items.id过滤器。

Mongoplayground链接

如果你想要在items中没有对象具有给定的id时过滤文档,只需在$match阶段$and数组中添加我添加的额外对象即可。

{
 $in: [
       1,
       "$items.id",
 ]
}

如果您不想过滤掉这些文档,但是想要过滤掉所有itemsitems.id不是给定ID的对象,我找到的唯一解决方案是使用在新的mongoplayground链接中添加的$project阶段。


什么是 ISOdateString?它可以是一个 Date 对象(在 MongoDB 中提供了一个别名叫做 ISODate),或者是一个 String - 没有其他的。 - Wernfried Domscheit
在 MongoDB 中,日期格式为:"date" : ISODate("2022-01-05T00:00:01.000Z"), 在代码中: const startDate = moment(req.query.startDate, 'YYYY-MM-DD').startOf('day').toDate() const endDate = moment(req.query.endDate, 'YYYY-MM-DD').endOf('day').toDate() 因此,它是 ISODate。 - Bob
谢谢!我正在使用if条件,例如if(req.query.startDate) {...},并将数据推入查询中而不是连接。 - Mike
@Anuj Pancholi,也许你可以帮我解决我的最后一个问题。请查看我的更新。谢谢。 - Bob
@Mike,你可以使用array1.push(...array2)代替array1=array1.concat(array2)。此外,如果你正在从req.queryreq.body动态构建查询,请参考这个链接。 @Bob,我会研究一下的。 - Anuj Pancholi
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接