【问题标题】:MongoDB query and projection on subdocument array returns also array of another document子文档数组上的 MongoDB 查询和投影还返回另一个文档的数组
【发布时间】:2019-01-13 16:19:04
【问题描述】:

我正在尝试查询嵌入的子文档,然后仅通过projection 在该子文档中返回一个数组。查询后,您可以选择要通过投影返回的字段。我想使用本机功能,因为它是可能的并且是最干净的方式。问题是它在两个文档中返回数组。

我尝试了不同的查询和投影选项,但没有结果。


用户模型

             // Define station schema
             const stationSchema = new mongoose.Schema({
                mac: String,
                stationName: String,
                syncReadings: Boolean,
                temperature: Array,
                humidity: Array,
                measures: [{
                    date: Date,
                    temperature: Number,
                    humidity: Number
                }],
                lastUpdated: Date
            });

            // Define user schema
            var userSchema = mongoose.Schema({

                apiKey: String,
                stations : [stationSchema]

            },  {
                    usePushEach: true 
                }
            );

api调用

       app.get('/api/stations/:stationName/measures',function(req, res, next) {

        var user = {
            apiKey: req.user.apiKey
        }

        const query = {
            apiKey: user.apiKey,
            'stations.stationName': req.params.stationName
        }

        const options = {
            'stations.$.measures': 1,
        }

        User.findOne(query, options)
        .exec()
        .then(stations => {     
            res.status(200).send(stations)
        })
        .catch(err => {
            console.log(err);
            res.status(400).send(err);
        })

    });

预期结果

   {
        "_id": "5c39c99356bbf002fb092ce9",
        "stations": [
            {
                "stationName": "livingroom",
                "measures": [
                    {
                        "humidity": 60,
                        "temperature": 20,
                        "date": "2019-01-12T22:49:45.468Z",
                        "_id": "5c3a6f09fd357611f8d078a0"
                    },
                    {
                        "humidity": 60,
                        "temperature": 20,
                        "date": "2019-01-12T22:49:46.500Z",
                        "_id": "5c3a6f0afd357611f8d078a1"
                    },
                    {
                        "humidity": 60,
                        "temperature": 20,
                        "date": "2019-01-12T22:49:47.041Z",
                        "_id": "5c3a6f0bfd357611f8d078a2"
                    }
                ]
            }
        ]
    }

实际结果

   {
        "_id": "5c39c99356bbf002fb092ce9",
        "stations": [
            {
                "stationName": "livingroom",
                "measures": [
                    {
                        "humidity": 60,
                        "temperature": 20,
                        "date": "2019-01-12T22:49:45.468Z",
                        "_id": "5c3a6f09fd357611f8d078a0"
                    },
                    {
                        "humidity": 60,
                        "temperature": 20,
                        "date": "2019-01-12T22:49:46.500Z",
                        "_id": "5c3a6f0afd357611f8d078a1"
                    },
                    {
                        "humidity": 60,
                        "temperature": 20,
                        "date": "2019-01-12T22:49:47.041Z",
                        "_id": "5c3a6f0bfd357611f8d078a2"
                    }
                ]
            },
******************************************************
 // this whole object should not be returned
            {
              "stationName": "office",
                "measures": [] 
            }
******************************************************
        ]
    }

编辑 下面的答案与聚合有效,但我仍然觉得我需要这么多代码很奇怪。如果在我的正常查询之后,我得到与“.stations[0].measures”相同的结果,而不是整个聚合管道:

.then(stations => {     
    res.status(200).send(stations.stations[0].measures)
})

我阅读代码的方式,上面的完全一样:

const options = {'stations.$.measures': 1}

美元符号在索引 0 中的位置,因为那是与查询部分匹配的车站索引:stationName: "livingroom"

谁能解释一下?

【问题讨论】:

  • 所以您只想要至少存在一种度量的站点?
  • 不,我只想要度量数组的内容,来自我在查询中查找的站: const query = { apiKey: user.apiKey, 'stations.stationName': req.params .stationName } 它应该只返回“客厅”的度量,但它也显示了车站“办公室”,如您在上面的结果中所见。有什么想法吗?

标签: node.js mongodb express


【解决方案1】:

这不是用 mongoose 来描述的,但这会在 1 个或多个文档的站点数组中找到特定的站点名称,并仅返回 measures 数组:

db.foo.aggregate([
// First, find the docs we are looking for:
{$match: {"stations.stationName": "livingroom"}}

// Got the doc; now need to fish out ONLY the desired station.  The filter will
// will return an array so use arrayElemAt 0 to extract the object at offset 0.
// Call this intermediate qqq:
,{$project: { qqq:
      {$arrayElemAt: [
          { $filter: {
            input: "$stations",
            as: "z",
            cond: { $eq: [ "$$z.stationName", "livingroom" ] }
      }}, 0]
      } 
}}

// Lastly, just project measures and not _id from this object:
,{$project: { _id:0, measures: "$qqq.measures" }}
                  ]);

【讨论】:

  • 这是第一个真正适用于原生猫鼬函数的答案。你能告诉我为什么投影在我做的例子中不起作用吗?你的效果更好,因为它只返回想要的数据,但我上面的问题是它还返回了一个站 dat 的度量数组,它与 de 查询中的 de station 名称不匹配。再次感谢!
【解决方案2】:

$elemMatch 运算符将查询结果中的数组字段的内容限制为仅包含与 $elemMatch 条件匹配的第一个元素。

在 Select Query 中尝试 $elemMatch 如下:

const query = {
     apiKey: user.apiKey,
     'stations.stationName': req.params.stationName
}
const options = {
   'stations' : {$elemMatch: { 'stationName' : req.params.stationName }}
}

【讨论】:

  • 感谢您的回答!我会试试这个,但它仍然不会选择并只返回度量数组,对吗?
  • 是的,试一试!根据您对问题的评论,它将返回请求的 stationName 的度量(预期结果)
猜你喜欢
  • 1970-01-01
  • 2016-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-22
  • 2013-10-04
  • 2014-06-08
  • 1970-01-01
相关资源
最近更新 更多