【问题标题】:MongoDB aggregation Shell script to MongoC# DriverMongoDB 聚合 Shell 脚本到 MongoC# 驱动程序
【发布时间】:2016-06-09 12:52:07
【问题描述】:

如何将此 Mongo Shell 脚本转换为 MongoDB C# 驱动程序?

var myItems = []

var myCursor = db.Tickets.aggregate(
   [
      { $match : { TicketProjectID : 49 } },
      { $project: { TicketProjectID:1, TicketID:1, concatValue: { $concat: [ "$Status", " - ", "$Name" ] } } }
    // I will have a list of fields that I need to concatenate at run time. So C# query should support concatenation for "N" number of fields at run-time.
      //{ $group: { _id: null, count: { $sum: 1 } } }

   ],
      { allowDiskUse: true }
)

   //This seems like a ugly performance approach when we are working against 100k results with above match
     while (myCursor.hasNext()) {
         var item = myCursor.next();
         if(item.concatValue.search(/mysearchkey/i) > -1)
             {
                myItems.push(item.TicketID)
             }
    }    
    myItems

或者有没有更好的方法在连接投影中进行字符串搜索,而不是在游标中进行 foreach,因为某些查询可能会获得 50k 条记录。

这是我迄今为止尝试过的,(不使用聚合)

注意:修剪此代码以适应公共问答网站。所以请将此视为伪代码

 var tickets = ticketsCollection.FindSync(filter).ToList();
                string concatinatedValue = string.Empty;
                foreach (var ticket in tickets)
                {
                    foreach (var field in customFieldsForThisProject)
                        concatinatedValue += ticket[field.Replace(" ", "_")];

                  if(concatinatedValue.StripHtml().contains("MysearchWord"))
                 {
                   TikectIdList.Add(ticket["TicketID"])
                 }
                }

【问题讨论】:

  • @KDecker 更新了我尝试过的问题。我没有尝试将聚合与 C# 驱动程序一起使用。

标签: c# mongodb shell mongodb-.net-driver mongo-shell


【解决方案1】:

感谢@Nikola.Lukovic 处理他的伪代码,我想出了这个可行的解决方案。

方法一:完全使用C#驱动

var ticketsCollection = _mongoConnect.Database.GetCollection<BsonDocument>("Tickets");

            var dbResult = from ticket in ticketsCollection.AsQueryable()
                select new
                {
                    TicketProjectID = ticket["TicketProjectID"],
                    TicketID = ticket["TicketID"],
                    ConcatValue = ticket["Status"] + (string) ticket["Name"]
                };
            var matches = from dbr in dbResult
                where dbr.ConcatValue.Contains(searchKey)
                where dbr.ConcatValue.StartsWith(searchKey)
                select dbr;

这不适用于我的场景,因为我正在尝试 连接是如果类型字符串,但$add 仅适用于 numericdate 类型。

方法二:使用RunCommand 并直接传递Shell 命令。 这适用于所有数据类型。也可以满足我的需要。

        var projectCommand =
            BsonDocument.Parse(
                "{ $project: { _id: -1, TicketProjectID:1, TicketID:1, concatValue: { $concat: [ \"$Status\", \" - \", \"$Name\" ] } } }");
        var matchCommand =
            BsonDocument.Parse("{ $match: {concatValue: { $regex: '" + searchKey + "', $options: 'i'} } }");

        var pipeline = new[] {projectCommand, matchCommand};
        var result = ticketsCollection.Aggregate<BsonDocument>(pipeline).ToList();
        if (result.Count > 0)
            return result.Select(x => (int)x["TicketID"]).ToList();
        return null;

【讨论】:

    【解决方案2】:

    根据给定的评论编辑

    如果你可以使用 AsQueryable() 你可以得到这样的值:

    var dbResult = from ticket in ticketsCollection.AsQueryable()
                   where ticket.TicketProjectID == 49
                   select new 
                   {
                       TicketProjectID = ticket.TicketProjectID,
                       TicketID = ticket.TicketID,
                       ConcatValue = ticket.Status + " - " + ticket.Name
                   };
    

    然后你可以做这样的事情:

    var result = from dbr in dbResult
                 where dbr.ConcatValue.Contains("something") //or
                 where dbr.ConcatValue.StartsWith("something")//or you can use regex
                 select dbr;
    

    注意:由于某种原因,Ticket 类型中的 StatusName 属性都需要属于 String 类型才能使串联工作,因为 mongo 驱动程序无法识别某些人对 ToString() 的调用其他类型。

    如果您想连接其他类型的属性,您可以从数据库中单独获取它们,而不是在本地连接它们。

    note, i'm not that good with mongo shell i could mess something up but you can see in which way you could go

    或者你可以这样写你的shell命令并将它放在一个字符串中:

    var command = @"db.Tickets.aggregate(
    [
        { $project: { TicketProjectID:1, TicketID:1, concatValue: { $concat: [ "$Status", " - ", "$Name" ] } } },
        { $match : { TicketProjectId : 49, concatValue : { $regex : /mysearchkey/i } } }
    ],
    { allowDiskUse : true }
    );";
    

    然后使用来自MongoDatabaseRunCommandAsync 方法在c# 中执行它。

    var result = await mongoDatabase.RunCommandAsync<BsonDocument>(BsonDocument.Parse(command));
    

    【讨论】:

    • TicketProjectID = 1 表示在结果中包含该字段并忽略其余部分。
    • 我需要这个动态的 "ticket.Status + " - " + ticket.Name" 我将有一个需要连接的字段列表,那么如何在运行时构建这个连接呢?
    • 那么我认为你当前的解决方案就是你得到的,除非你有可能在你的查询和 mongodb 驱动程序之间注入类似LinqToQueryString 的东西
    • 我可以像从 C# 一样执行 Shell 脚本吗?
    • 不得不做更多的改变,但终于可以得到我需要的东西
    猜你喜欢
    • 2011-10-23
    • 2019-08-03
    • 1970-01-01
    • 2020-05-18
    • 1970-01-01
    • 1970-01-01
    • 2020-06-21
    • 2016-08-03
    • 2016-02-11
    相关资源
    最近更新 更多