将MongoDB聚合Shell脚本转换为MongoC#驱动程序

4

我该如何将这个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#驱动程序进行聚合。 - HaBo
2个回答

3
感谢 @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只能用于数值和日期类型,这种方法对我的情况不起作用。

方法二:使用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;

注意:由于mongo驱动程序不会识别来自其他类型的ToString()调用,因此类型Ticket的Status和Name属性都需要是String类型才能进行连接。
如果要连接来自其他类型的属性,则可以从数据库中单独获取它们,然后在本地进行连接。
请注意,我对mongo shell并不是很熟悉,可能会出错,但您可以看到应该如何操作。
或者,您可以像这样编写shell命令并将其放入字符串中:
var command = @"db.Tickets.aggregate(
[
    { $project: { TicketProjectID:1, TicketID:1, concatValue: { $concat: [ "$Status", " - ", "$Name" ] } } },
    { $match : { TicketProjectId : 49, concatValue : { $regex : /mysearchkey/i } } }
],
{ allowDiskUse : true }
);";

然后使用 MongoDatabase 中的 RunCommandAsync 方法在 c# 中执行它。

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

TicketProjectID = 1 表示在结果中包含此字段并忽略其余部分。 - HaBo
我需要这个动态字符串,即 "ticket.Status + " - " + ticket.Name"。我将有一个需要连接的字段列表,那么我如何在运行时构造这个连接? - HaBo
我认为你现在的解决方案就是你所得到的,除非你有可能在查询和MongoDB驱动程序之间注入LinqToQueryString这样的东西。 - Nikola.Lukovic
我能直接从C#执行Shell脚本吗? - HaBo
1
不得不进行一些更改,但最终终于得到了我所需要的。 - HaBo
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接