问题
I have next 3 documents in mongodb:
document 1:
{
    "name": "device1",
    "camera": {
        "number": 3
    }
}
document 2:
{
    "name": "device2",
    "camera": {
        "number": 1
    }
}
document 3:
{
    "name": "device3",
    "wifi": {
        "number": 2
    }
}
My aim is to find all devices which modules' number > 1, the module maybe camera, wifi or others.
I know I can use next to get the device:
> db.devices.find({"camera.number":{$gt:1}})
{ "_id" : ObjectId("5f436a3df716cb47d319245e"), "name" : "device1", "camera" : { "number" : 3 } }
> db.devices.find({"wifi.number":{$gt:1}})
{ "_id" : ObjectId("5f436a58f716cb47d3192460"), "name" : "device3", "wifi" : { "number" : 2 } }
But it looks I had to add something like "module.number" in query, you know maybe I have a lots of modules, then not so efficient to use camera.number, wifi.number & othermodule.number to find all matched devices. If possible I can have something magic to directly get the device which "has any module's number > 1", I mean no need to specify the parent field?
回答1:
I don't think it is possible with find() method but you can try aggregate() method,
- $addFields will add devicefield, which convert$$ROOTobject to array inkandvformat using $objectToArray
- $match you can match device.v.numberto your number
- $project to hide devicefield
db.devices.aggregate([
  { $addFields: { device: { $objectToArray: "$$ROOT" } } },
  { $match: { "device.v.number": { $gt: 1 } } },
  { $project: { device: 0 } }
])
Playground
Another Possible Way with aggregate() method,
- match with $expr
- $reduce will input $$ROOTas$objectToArrayand insideinchecks condition if number is null using $ifNull then$addnumber in initialValue otherwise add0.
db.collection.aggregate([
  {
    $match: {
      $expr: {
        $gt: [
          {
            $reduce: {
              input: { $objectToArray: "$$ROOT" },
              initialValue: 0,
              in: { $add: ["$$value", { $ifNull: ["$$this.v.number", 0] }] }
            }
          },
          1 // add your search number
        ]
      }
    }
  }
])
Playground
回答2:
Simple, just change your schema.
https://mongoplayground.net/p/npSvVzbnsyk
  {
    "name": "device1",
    "modules": [
      {
        "k": "camera",
        "v": 3
      }
    ]
  },
  {
    "name": "device2",
    "modules": [
      {
        "k": "wifi",
        "v": 3
      },
      {
        "k": "camera",
        "v": 2
      }
    ]
  },
  {
    "name": "device3",
    "modules": [
      {
        "k": "wifi",
        "v": 2
      }
    ]
  }
db.collection.find({"modules.v": 3})
来源:https://stackoverflow.com/questions/63556589/how-to-directly-query-nested-field-without-specify-parent-field