【问题标题】:What is the best way to query an array of subdocument in MongoDB?在 MongoDB 中查询子文档数组的最佳方法是什么?
【发布时间】:2021-09-23 21:07:33
【问题描述】:

假设我有一个这样的集合:

    {
    "id": "2902-48239-42389-83294",
    "data": {
        "location": [
            {
                "country": "Italy",
                "city": "Rome"
            }
        ],
        "time": [
            {
                "timestamp": "1626298659",
                "data":"2020-12-24 09:42:30"
            }
        ],
        "details": [
            {
                "timestamp": "1626298659",
                "data": {
                    "url": "https://example.com",
                    "name": "John Doe",
                    "email": "john@doe.com"    
                }
            },
            {
                "timestamp": "1626298652",
                "data": {
                    "url": "https://www.myexample.com",
                    "name": "John Doe",
                    "email": "doe@john.com"    
                }
            },
            {
                "timestamp": "1626298652",
                "data": {
                    "url": "http://example.com/sub/directory",
                    "name": "John Doe",
                    "email": "doe@johnson.com"    
                }
            }
        ]
    }
}

现在主要关注子文档数组(“data.details”):我只想获得相关匹配的输出,例如:

db.info.find({"data.details.data.url": "example.com"})
  1. 如何获得所有“data.details.data.url”包含“example.com”但与“myexample.com”不匹配的匹配项。 当我使用 $regex 执行此操作时,我得到的结果太多,所以如果我查询“example.com”,它也会返回“myexample.com”

  2. 即使我确实得到了部分结果(使用 $match),它也很慢。我试过这个聚合阶段

       { $unwind: "$data.details" },
    
       {
         $match: {
           "data.details.data.url": /.*example.com.*/,
         },
       },
       {
         $project: {
           id: 1,
           "data.details.data.url": 1,
           "data.details.data.email": 1,
         },
       },
    
  3. 我真的不明白这种模式,使用 $match,Mongo 有时会识别像“https://”或“https://www”这样的前缀。有时它不会。

更多信息: 我的收藏有几十GB,我创建了两个索引:

  • 像这样复合: “data.details.data.url”:1, “data.details.data.email”:1
  • 文本索引: "data.details.data.url": "文本", "data.details.data.email": "文本"

它确实提高了查询性能,但还不够,我仍然遇到 $match 与 $regex 的问题。感谢帮助!

【问题讨论】:

  • 对于正则表达式部分,您可能想尝试类似 "http[s]*://example.com*"

标签: mongodb mongoose mongodb-query aggregation-framework mongodb-indexes


【解决方案1】:

您的错误在于正则表达式。它匹配所有 URL,因为子字符串 example.com 在所有 URL 中。例如:https://www.myexample.com 匹配粗体部分。

为避免这种情况,您必须使用另一个正则表达式,例如以该域开头的正则表达式。

例如:

(http[s]?:\/\/|www\.)YOUR_SEARCH

将检查您要搜索的内容是否位于 http:// 或 www 后面。分数。 https://regex101.com/r/M4OLw1/1

我把完整的查询留给你。

[
  {
    '$unwind': {
      'path': '$data.details'
    }
  }, {
    '$match': {
      'data.details.data.url': /(http[s]?:\/\/|www\.)example\.com/)
    }
  }
]

注意:您必须从正则表达式中转义特殊字符。点匹配任何字符,斜杠将关闭您的正则表达式,从而导致错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-20
    • 2017-11-28
    • 1970-01-01
    • 2019-08-01
    相关资源
    最近更新 更多