【问题标题】:How to specify fields in MongoDB with multiple condition find query?如何使用多个条件查找查询在 MongoDB 中指定字段?
【发布时间】:2019-03-15 09:32:00
【问题描述】:

这是单个文档:

{
   _id: "...",
   firstName: "john",
   lastName:"Doe",
   cars: [
       {
           "_id": "...",
           "carName": "BMW",
           "carModel": "330",
           "carColor": "silver"
       },
       {
           "_id": "...",
           "carName": "Lexus",
           "carModel": "IS300",
           "carColor": "white"
       },
       {
           "_id": "...",
           "carName": "LADA",
           "carModel": "2106",
           "carColor": "blue"
       }
   ]
}

我正在尝试仅选择 John's BMW 的“carColor”。 像这样的:

db.persons.findOne(
        { "firstName": "John", "cars.carName": "BMW" },
        { "_id": 0, "cars.$.carColor": 1 }
      );

但是这个查询返回完整的对象是这样的:

{
    cars: [
      {
         "_id": "...",
         "carName": "BMW",
         "carModel": "330",
         "carColor": "silver"
      }
}

我已经尝试了不同的查询,但没有 .$。符号:

db.persons.findOne(
            { "firstName": "John", "cars.carName": "BMW" },
            { "_id": 0, "cars.carColor": 1 }
          );

此版本仅返回“carColor”属性,但不过滤“carName”。 像这样:

{
   cars: [
       {
          "carColor": "silver"
       },
       {
          "carColor": "white"
       },
       {
          "carColor": "blue"
       }
   ]
}

有什么想法吗?

【问题讨论】:

    标签: arrays database mongodb mongoose mongodb-query


    【解决方案1】:

    为什么它不起作用?

    {"firstName": "John", "cars.carName": "BMW"}

    表示“名字是 john,并且汽车数组中至少有一个条目,其中 carName 是“BMW””。但它返回完整的文档,没有过滤数组。

    { "_id": 0, "cars.carColor": 1 }

    不投影_id,而是投影cars数组所有条目的carColor。

    解决方案

    事实上,使用 find 和 projection 方法并不能完全达到您想要的效果。你可以做的更好的是像这样添加$ projection operator

    db.collection.find({
      firstName: "john",
      "cars.carName": "BMW"
    },
    {
      _id: 0,
          "cars.$": 1
        })
    
    **RESULT**
    
    [
      {
        "cars": [
          {
            "_id": "...",
            "carColor": "silver",
            "carModel": "330",
            "carName": "BMW"
          }
        ]
      }
    ]
    

    但是这种方法有缺点:

    • 您可以获得整个数组条目,而不仅仅是您想要/需要的颜色
    • 它只返回第一个匹配的条目:如果 john 有 2 辆 BMW,则只返回一个。

    更好的解决方案

    幸运的是,MongoDB 提供了另一种方式来实现这一点,即聚合框架和$filter 运算符:

    db.collection.aggregate([
      {
        $match: {
          firstName: "john"
        }
      },
      {
        $project: {
          cars: {
            $filter: {
              input: "$cars",
              as: "cars",
              cond: {
                $eq: [
                  "$$cars.carName",
                  "BMW"
                ]
              }
            }
          }
        }
      },
      {
        $project: {
          _id: 0,
          "colors": "$cars.carColor"
        }
      }
    ])
    

    You can try it here.

    编辑:其他解决方案

    你也可以试试这个,放松/分组阶段:

    db.collection.aggregate([
      {
        $match: {
          firstName: "john"
        }
      },
      {
        $unwind: "$cars"
      },
      {
        $match: {
          "cars.carName": "BMW"
        }
      },
      {
        $group: {
          "_id": null,
          colors: {
            $push: "$cars.carColor"
          }
        }
      }
    ])
    

    【讨论】:

      【解决方案2】:
      db.persons.find({
        firstName: 'john',
        cars: {
          $elemMatch: {
            carName: 'BMW'
          }
        }
      },
      {
        'cars.$': 1
      })
      

      【讨论】:

        【解决方案3】:

        如果您知道数组中的“BMW”值不超过一个,那么这是一种使用单个$project 阶段获取结果的方法:

        db.getCollection('collection').aggregate([{
            $match: {
                "firstName": "john"
                /* for performance reasons, you may want to include the following line which, however, is not required */
                /* this makes sense if you have lots of "john"s with different sets of cars in your database */
                , "cars.carName": "BMW" // this will use an index on "cars.carName" if available
            }
        }, {
            $project: {
                _id: 0, // do not return the _id field
                color: {
                    $reduce: { // transform the filtered input array
                        "input": {
                            $filter: { // remove all non-"BMW" cars from the "cars" array
                                input: "$cars",
                                as: "car",
                                cond: { $eq: [ "$$car.carName", "BMW" ] }
                            }
                        },
                        "initialValue": null,
                        "in": "$$this.carColor" // just return the color value, nothing else
                    }
                }
            }
        }])
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-05-22
          • 2018-11-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-09
          • 2016-04-19
          相关资源
          最近更新 更多