【问题标题】:How to $pull Multiple Objects from an Array by Multiple Criteria如何通过多个条件从数组中提取多个对象
【发布时间】:2016-07-18 07:36:35
【问题描述】:

我有一种情况,我必须根据请求从数组中提取多个值。

数据库中的事物状态:

{
    "_id" : ObjectId("56fb8fdf5e3227c637891ca8"),
    "description" : "Testing service",
    "name" : "test-service",
    "endpoints" : [ 
        {
            "uri" : "/api/test1",
            "method" : "GET",
            "description" : "test1",
            "noAuthRequired" : true,
            "allowedByDefault" : true,
            "allowedRoles" : ['admin']
        },
        {
            "uri" : "/api/test2",
            "method" : "GET",
            "description" : "test2",
            "noAuthRequired" : true,
            "allowedByDefault" : true,
            "allowedRoles" : ['admin']
        },
        {
            "uri" : "/api/test3",
            "method" : "GET",
            "description" : "test3",
            "noAuthRequired" : true,
            "allowedByDefault" : true,
            "allowedRoles" : ['admin']
        }
    ]
}

请求列出了我必须从数据库数组中删除的多个端点。 JSON 请求示例:

{
    "endpoints": [{
        "uri": "/api/test1",
        "method": "GET"
    },
    {
        "uri": "/api/test2",
        "method": "POST"
    }]
}

当这个请求到来并得到处理时,它应该删除带有 URI /api/test1 和方法 GET 的端点。它不应该删除带有 URI /api/test2 和方法 GET 的端点,因为请求指出 POST /api/test2 应该被删除,并且由于它不存在于 DB 中,因此只有 GET /api/test1 被删除。

我尝试过使用 Mongoose 这样做:

router.route('/services/:id/endpoints').delete(function(req, res) {
    ...
    model.service.findOneAndUpdate({ '_id': req.params.id },
    { $pull: { 'endpoints': req.body.endpoints } },
    function(err, srv) {
        ...
    });
});

这根本没有任何作用。

router.route('/services/:id/endpoints').delete(function(req, res) {
    ...
    model.service.findOneAndUpdate({ '_id': req.params.id },
    { $pullAll: { 'endpoints': req.body.endpoints } },
    function(err, srv) {
        ...
    });
});

这也不起作用。

router.route('/services/:id/endpoints').delete(function(req, res) {
    ...
    model.service.findOneAndUpdate({ '_id': req.params.id },
    { $pullAll: { 'endpoints': { $in: req.body.endpoints } } },
    function(err, srv) {
        ...
    });
});

这会删除数据库中的所有端点,这是不应该的。

我已经决定使用异步:

var pullCalls = [];
req.body.endpoints.forEach(function(endpoint) {
  pullCalls.push(function(callback) {
    model.service.findOneAndUpdate({
      '_id': req.params.id
    }, {
      $pull: {
        'endpoints': {
          'method': endpoint.method,
          'uri': endpoint.uri
        }
      }
    }, function(err, srv) {
      if (err)
        return callback(err);
      callback(err, srv);
    });
  });
});

// TODO: try doing this without async in a single query
async.parallel(pullCalls, function(err, srv) {
  if (err) {
    res.status(500);
    res.json({
      'success': false,
      'response': err
    });
  } else {
    res.json({
      'success': true,
      'response': 'endpoints_removed'
    });
  }
});

这行得通,但我想在单个 mongoose 查询中不使用异步。有办法吗?

谢谢你:)

【问题讨论】:

    标签: node.js mongodb mongoose mongodb-query


    【解决方案1】:

    你会讨厌这个,但是:

    { "$pull": { "endpoints": { "$or": req.body.endpoints } } }
    

    可以正常工作。

    $or 运算符要求数据格式与您提交的格式完全相同。而$pull 已经在本质上对数组字段元素进行检查。

    当然$or 的意思是“任何一个”,基本上翻译为“任何符合这两个条件的任何东西都需要被拉取”。

    只要req.body.endpoints 像你说的那样实际上表示为一个数组,那么这实际上就是$or 的正确参数

    【讨论】:

    • 谢谢你的工作!我什至不知道 $ 或存在 :D
    • @FilipVoska 您实际上与$in 的关系如此接近,但当然该运算符只需要“值”的“列表”而不是“完整文档表达式” .所以支持你的尝试,这比很多人在这里问的要好得多。此外,您可能会感到困惑 $in 不是“专门”用于数组的运算符。相反,它是一个“匹配字段的参数数组”,无论该字段是否实际上是一个数组本身。将其视为“$or 的简写” 的最佳方式。事实上,确实如此。
    • 尝试使用 $pullAll 而不是 $pull
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-23
    • 2015-03-10
    • 1970-01-01
    • 2021-03-06
    • 1970-01-01
    • 1970-01-01
    • 2023-02-07
    相关资源
    最近更新 更多