如何搜索旅行的好地方(MongoDb LINQ和.NET Core)

目录

涵盖的主题

安装

MongoDB配置

MongoImport –使用大型数据集初始化数据库

MongoDB – LINQ支持

如何在特定城市中找到要做的事情

运行更快的查询

组项目

接下来


让我们使用.NET CoreMongoDb构建一个简单的WebApi,以查询全球不同目的地的详细信息。我们将使用运行于不同场景的MongoDb LINQ进行搜索。

有关如何使用MongoDB构建和测试完整的.NET CORE WebApi的简要介绍,请查看我之前的文章:将MongoDB .NET驱动程序与.NET Core WebAPI一起使用

本文继续其他两个部分:

  • 第2部分– MongoDB中的分页–如何真正避免性能下降?
  • 第3部分– MongoDb和LINQ:如何汇总和加入集合

您可以在GitHub上找到该项目:github.com/fpetru/WebApiQueryMongoDb

在本文中,我将使用两个数据集:

  • Wikivoyage提供了全球最受旅行者欢迎的博物馆、景点、餐厅和酒店的更多详细信息。原始数据集可以从下一个url访问。
  • 第二个数据集来自GeoNames,它是一个覆盖所有国家的地理数据库。出于演示目的,我只选择了人口超过5000的城市。

使用这些数据集,可以更轻松地运行一些示例查询,以检索一致数量的数据。

涵盖的主题

  • MongoDb –安装和安全设置
  • MongoDB –使用mongoimport工具
  • 制作一个完整的ASP.NET WebApi项目,使用MongoDB C#Driver v.2异步连接
  • 运行LINQ查询

安装

这是所有需要安装的东西:

  • Visual Studio Community 2017,包括.NET Core选项
  • MongoDBRobomongo

MongoDB配置

安装MongoDB之后,您将需要配置访问权限以及数据所在的位置。

为此,请在本地创建一个名为mongod.cfg的文件。这将包括设置到MongoDB服务器的数据文件夹以及到MongoDB日志文件的路径,最初不进行任何身份验证(最后两行被注释)。请使用您的本地设置更新这些本地路径

systemLog:
  destination: file
  path: "C:\\tools\\mongodb\\db\\log\\mongo.log"
  logAppend: true
storage:
  dbPath: "C:\\tools\\mongodb\\db\\data"

#Once the admin user is created, remove the comments, and let the authorization be enabled
#security:
#  authorization: enabled

命令提示符下运行。这将启动MongoDB服务器,指向已经创建的配置文件(如果服务器安装在自定义文件夹中,请首先更新命令)

"C:\Program Files\MongoDB\Server\3.4\bin\mongod.exe" --config C:\Dev\Data.Config\mongod.cfg

服务器启动后(您可以在日志文件中看到详细信息),在命令提示符下运行mongo.exe 。下一步是将管理员用户添加到数据库中。使用完整路径(例如:C:\Program Files\MongoDB\Server\3.4\bin\mongo.exe)运行MongoDB,然后将以下代码复制并粘贴到控制台中:

use admin
db.createUser(
  {
    user: "admin",
    pwd: "abc123!",
    roles: [ { role: "root", db: "admin" } ]
  }
);
exit;

停止服务器,从mongod.cfg文件中取消最后两行的注释,然后重新启动MongoDb服务器。

MongoImport –使用大型数据集初始化数据库

我们将从Wikivoyage开始。该数据集最初在此处可用(链接)。为了更轻松地导入它,我对其进行了稍微的转换(更改为制表符分隔的文件,并应用了最小限度的数据清理)。该文件位于Github中(链接)。

第二个数据集GeoNames在同一个Github文件夹(链接)中可用。

运行脚本import.bat(与datsets位于同一文件夹中),将导入数据,并创建一个名为TravelDb的新数据库和相关索引。脚本包含在此处,但是最好只运行脚本文件:

mongoimport --db TravelDb ^
            --collection WikiVoyage ^
            --type tsv ^
            --fieldFile enwikivoyage-fields.txt^
            --file enwikivoyage-20150901-listings.result.tsv^
            --columnsHaveTypes^
            --username admin ^
            --password abc123! ^
            --authenticationDatabase admin ^
            --numInsertionWorkers 4

mongoimport --db TravelDb ^
            --collection Cities ^
            --type tsv ^
            --fieldFile cities5000-fields.txt^
            --file cities5000.txt ^
            --columnsHaveTypes^
            --username admin ^
            --password abc123! ^
            --authenticationDatabase admin ^
            --numInsertionWorkers 4

字段文件指定字段名称及其关联的类型。使用optionsHaveTypes选项,我们可以使用所需的类型(例如,intdoublestring等)进行导入。

结果应如下所示:

如何搜索旅行的好地方(MongoDb LINQ和.NET Core)_第1张图片

MongoDB – LINQ支持

此处包含的.NET Core解决方案采用与我以前的文章(MongoDB .NET驱动程序与.NET Core WebAPI结合使用)相同的结构。在那里,我已经提供了按步操作指南,内容涉及如何从头开始创建WebApi解决方案,连接到MongoDB以及实现REST API的所有基本操作。

相比之下,此处,Web控制器将仅执行一个操作(GET主要集中于运行不同的查询:

[NoCache]
[HttpGet]
public Task> Get()
{
    return GetTravelItemsInternal();
}

private async Task> GetTravelItemsInternal()
{
    return await _travelItemRepository.GetTravelItems();
}

在后台,查询使用LINQ语法运行,并返回前500条记录。

public async Task> GetTravelItems()
{
    try
    {
        return await _context.TravelItems.Take(500).ToListAsync();
    }
    catch (Exception ex)
    {
        // log or manage the exception
        throw ex;
    }
}

该查询在服务器上呈现,并且我们仅接收有限的数据集。这是可能的,因为我们拥有由MongoDB C#驱动程序本地提供的IQueryable类型接口。

...
using MongoDB.Driver.Linq;
...
public IMongoQueryable TravelItems
{
    get
    {
        return _database.GetCollection("WikiVoyage").AsQueryable();
    }
}

如何在特定城市中找到要做的事情

假设我们想找到在城市中要做的有趣的事情。我们要么按照动作类型显示城市中的所有物品,要么只选择一个特定的动作(例如,买,做,吃,喝等)。

public async Task> GetTravelItems(string cityName, string action)
{
    try
    {
        if (action != null)
                    return await _context.TravelItems
                        .Where(p => p.City == cityName && p.Action == action).ToListAsync();

        return await _context.TravelItems.Where(p => p.City == cityName)
                    .OrderBy(p => p.Action)
                    .ToListAsync();
    }
    catch (Exception ex)
    {
        // log or manage the exception
        throw ex;
    }
}

该方法将由GET函数调用。假设我们要搜索在巴黎要做的有趣的事情(http://localhost:61612/api/travelquery/Paris?doAction=do),我们会得到有趣的结果,其中一个如下所示:

如何搜索旅行的好地方(MongoDb LINQ和.NET Core)_第2张图片

运行更快的查询

一种提高查询速度的方法是应用索引。建议在CityAction之后在集合中进行搜索,建议使用这两个字段添加一个简单的索引。

使用mongo shell执行JavaScript文件,将在City上添加索引,然后在Action上添加索引。

db = db.getSiblingDB('TravelDb');
db.WikiVoyage.createIndex( { City: 1, Action: 1 } );

检索速度将从平均0.150毫秒增加到大约0.001毫秒。

组项目

如果我们只想看到头条新闻该怎么办?无需详细说明哪些类型的操作可用于特定城市?

一个按城市操作字段分组的查询示例为:

await _context.TravelItems
            .GroupBy(grp => new { grp.City, grp.Action })
            .Select(g => new { g.Key.City, g.Key.Action }).ToListAsync();

接下来

我将创建本文的第二部分,添加分页支持以及较新的MongoDB版本带来的聚合增强功能,同时还要考虑第二个数据集。也许你知道这些,也许你学到了一些东西。您想看到更多东西吗?

你可能感兴趣的:(ASP.NET,CORE,架构及框架,MongoDb,LINQ,.NET,Core)