当前位置: 首页 > 面试题库 >

MongoDB查询优化

凌黎明
2023-03-14
问题内容

我希望从我的用户模型中检索一些信息,如下所示:

var userSchema = new mongoose.Schema({
  email: { type: String, unique: true, lowercase: true },
  password: String,

  created_at: Date,
  updated_at: Date,

  genre : { type: String, enum: ['Teacher', 'Student', 'Guest'] },
  role : { type: String, enum: ['user', 'admin'], default: 'user' },
  active : { type: Boolean, default: false },

  profile: {
    name : { type: String, default: '' },
    headline : { type: String, default: '' },
    description : { type: String, default: '' },
    gender : { type: String, default: '' },
    ethnicity : { type: String, default: '' },
    age : { type: String, default: '' }
  },

  contacts : {
    email : { type: String, default: '' },
    phone : { type: String, default: '' },
    website : { type: String, default: '' }
  },

  location : {
    formattedAddress : { type: String, default: '' },
    country : { type: String, default: '' },
    countryCode : { type: String, default: '' },
    state : { type: String, default: '' },
    city : { type: String, default: '' },
    postcode : { type: String, default: '' },
    lat : { type: String, default: '' },
    lng : { type: String, default: '' }
  }
});

在主页中,我有一个 位置 过滤器,您可以在其中浏览来自国家或城市的用户。

所有字段还包含其中的用户数:

United Kingdom
  All Cities (300)
  London (150)
  Liverpool (80)
  Manchester (70)
France
  All Cities (50)
  Paris (30)
  Lille (20)
Nederland
  All Cities (10)
  Amsterdam (10)
Etc...

在主页上,然后我还有“学生和老师”页面,我希望仅提供有关这些国家和城市有多少老师的信息…

我想做的是创建一个对MongoDB的查询,以通过单个查询检索所有这些信息。

此刻查询如下:

User.aggregate([
    { 
      $group: { 
        _id: { city: '$location.city', country: '$location.country', genre: '$genre' },
        count: { $sum: 1 }
      }
    },
    {
      $group: { 
        _id: '$_id.country',
        count: { $sum: '$count' },
        cities: { 
          $push: { 
            city: '$_id.city', 
            count: '$count'
          }
        },
        genres: {
          $push: {
            genre: '$_id.genre',
            count: '$count'
          }
        }
      }
    }
  ], function(err, results) {
    if (err) return next();
    res.json({ 
        res: results
    });
  });

问题是我不知道如何获取所需的所有信息。

  • 我不知道如何获得每个国家/地区的用户总数。
  • 我有每个国家/地区的用户长度。
  • 我有每个城市的用户长度。
  • 除了特定类型,我不知道该如何获得。

是否可以在Mongo中通过一次查询获得所有这些信息?

除此以外:

像这样向Mongo发送2、3个不同的请求来创建少量承诺:

getSomething
.then(getSomethingElse)
.then(getSomethingElseAgain)
.done

我敢肯定,每次存储指定的数据都会更容易,但是: 当数据库中有5000/10000以上的用户时,这样做对性能有好处吗?

抱歉,但是我仍在学习中,我认为这些对于理解MongoDB的性能/优化至关重要。

谢谢


问题答案:

您想要的是“分面搜索”结果,您可以在其中保存有关当前结果集中匹配词条的统计信息。随后,虽然有些产品“出现”可以在一个响应中完成所有工作,但您必须考虑到大多数通用存储引擎将需要多次操作。

使用MongoDB,您可以使用两个查询本身获取结果,并使用另一个查询获取构面信息。这将提供与专用搜索引擎产品(例如Solr或ElasticSearch)可用的多方面结果相似的结果。

但是为了有效地执行此操作,您希望以一种可以有效使用它的方式将其包含在文档中。对于您想要的一种非常有效的形式是使用标记化数据数组:

 {
     "otherData": "something",
     "facets": [
         "country:UK",
         "city:London-UK",
         "genre:Student"
     ]
 }

因此,“要素”是文档中的单个字段,而不是多个位置。这使得索引和查询变得非常容易。然后,您可以有效地汇总结果,并获取每个方面的总数:

User.aggregate(
    [
        { "$unwind": "$facets" },
        { "$group": {
            "_id": "$facets",
            "count": { "$sum": 1 }
        }}
    ],
    function(err,results) {

    }
);

或更理想的情况是
$match


User.aggregate(
    [
        { "$match": { "facets": { "$in": ["genre:student"] } } },
        { "$unwind": "$facets" },
        { "$group": {
            "_id": "$facets",
            "count": { "$sum": 1 }
        }}
    ],
    function(err,results) {

    }
);

最终给出如下响应:

{ "_id": "country:FR", "count": 50 },
{ "_id": "country:UK", "count": 300 },
{ "_id": "city:London-UK", "count": 150 },
{ "_id": "genre:Student": "count": 500 }

这样的结构很容易遍历和检查诸如离散的“国家”和属于“国家”的“城市”之类的东西,因为该数据始终由连字符“-”分隔。

试图将数组中的文档混搭是一个坏主意。BSON大小限制为16MB,从中将结果混在一起(特别是如果您要保留文档内容),肯定会超出响应范围。

对于像从这样的查询中获得结果的“总计数”这样简单的事情,只需将特定构面类型的元素相加即可。或者只是对.count()操作发出相同的查询参数:

User.count({ "facets": { "$in": ["genre:Student"] } },function(err,count) {

});

如此处所述,特别是在实现结果的“分页”时,获取“结果计数”,“实际计数”和实际的“结果页”的角色都被委派给服务器的“分离”查询。

将这些查询中的每一个并行提交到服务器,然后组合一个结构以馈送到您的模板或应用程序,这看上去很像来自提供这种响应的搜索引擎产品之一的多面搜索结果,这没什么错。

总结

因此,在文档中放置一些内容以在各个位置标记构面。标记字符串数组可以很好地达到此目的。它也适用于查询选择形式,例如
$in
和,
$all
用于方面选择组合上的“或”或“和”条件。

不要仅仅为了匹配某种感知的层次结构而尝试混搭结果或嵌套添加的内容,而要遍历接收到的结果并在令牌中使用简单的模式。这很简单

对内容运行分页查询,作为对方面或总体计数的单独查询。尝试将所有内容推入数组,然后仅进行计数限制是没有意义的。同样的情况也适用于RDBMS解决方案,以执行相同的操作,其中分页结果计数和当前页是单独的查询操作。

在MongoDB博客上有更多有关MongoDB的分面搜索的信息,该信息还介绍了其他一些选项。也有关于使用mongoconnector或其他方法与外部搜索解决方案集成的文章。



 类似资料:
  • 查询条件: {a:1,b:undefined}, {a:1,b:null}, mongodb查询,会忽略上述b字段吗?

  • 本文向大家介绍MongoDB查询性能优化验证及验证,包括了MongoDB查询性能优化验证及验证的使用技巧和注意事项,需要的朋友参考一下 结论: 1、 200w数据,合理使用索引的情况下,单个stationId下4w数据。mongodb查询和排序的性能理想,无正则时client可以在600ms+完成查询,qps300+。有正则时client可以在1300ms+完成查询,qps140+。 2、 Mon

  • 我需要有关嵌套对象数组的查询优化的帮助。 我们有大量文档的集合,每个文档都包含嵌套的对象数组,最高可达3rd级,如下所示: 集合名称:产品 收集文件总数:2000万 每个文档的大小: 我为我的产品集合添加了以下索引,如下所示:, > products.id索引 { “id”:1 } 嵌套数组文档的索引 { " products . sellers . seller _ id ":1 } 我的疑问:

  • 我使用Nodejs和MongoDB与expressjs和mongoose库,创建一个具有用户、文章和评论模式的博客API。下面是我使用的模式。

  • 问题内容: 我有一个博客系统,可将上传的文件存储到GridFS系统中。问题是,我不知道如何查询它! 我将Mongoose与尚未支持GridFS的NodeJS一起使用,因此我将实际的mongodb模块用于GridFS操作。没有SEEM可以像常规集合中的文档一样查询文件元数据。 将元数据存储在指向GridFS objectId的文档中是否明智?可以轻松查询? 任何帮助将不胜感激,我有点卡住了:/ 问题

  • 我在MongoDB中有以下表单的集合。正如您所看到的,有些文档有两个成员“id”和“xid”,而有些文档只有1个“id”(除了对象_id之外) 我想创建一个mongoexport语句,它将ID和xid值都>0的文档导出到仅csv的文档