diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/Filters/ConversationFilter.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/Filters/ConversationFilter.cs
index c31c87cb..df31faa1 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Repositories/Filters/ConversationFilter.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/Filters/ConversationFilter.cs
@@ -21,11 +21,16 @@ public class ConversationFilter
///
/// Check whether each key in the list is in the conversation states and its value equals to target value if not empty
///
- public IEnumerable States { get; set; } = new List();
+ public List States { get; set; } = new List();
}
public class KeyValue
{
public string Key { get; set; }
public string? Value { get; set; }
+
+ public override string ToString()
+ {
+ return $"Key: {Key}, Value: {Value}";
+ }
}
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs
index 075efc2b..4f1c5194 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs
@@ -1,5 +1,3 @@
-using BotSharp.Plugin.MongoStorage.Models;
-
namespace BotSharp.Plugin.MongoStorage.Collections;
public class AgentDocument : MongoBase
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationDialogDocument.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationDialogDocument.cs
index 21444c04..b71ae40c 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationDialogDocument.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationDialogDocument.cs
@@ -1,5 +1,3 @@
-using BotSharp.Plugin.MongoStorage.Models;
-
namespace BotSharp.Plugin.MongoStorage.Collections;
public class ConversationDialogDocument : MongoBase
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationStateDocument.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationStateDocument.cs
index 1f8f0e90..c6068a1b 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationStateDocument.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationStateDocument.cs
@@ -1,5 +1,3 @@
-using BotSharp.Plugin.MongoStorage.Models;
-
namespace BotSharp.Plugin.MongoStorage.Collections;
public class ConversationStateDocument : MongoBase
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/LlmCompletionLogDocument.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/LlmCompletionLogDocument.cs
index f04cb46c..f5b96c0a 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/LlmCompletionLogDocument.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/LlmCompletionLogDocument.cs
@@ -1,5 +1,3 @@
-using BotSharp.Plugin.MongoStorage.Models;
-
namespace BotSharp.Plugin.MongoStorage.Collections;
public class LlmCompletionLogDocument : MongoBase
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs
index dfbbfbaa..50647776 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs
@@ -40,6 +40,19 @@ public class MongoDbContext
return collection;
}
+ private IMongoCollection CreateConversationStateIndex()
+ {
+ var collection = Database.GetCollection($"{_collectionPrefix}_ConversationStates");
+ var indexes = collection.Indexes.List().ToList();
+ var stateIndex = indexes.FirstOrDefault(x => x.GetElement("name").ToString().StartsWith("States.Key"));
+ if (stateIndex == null)
+ {
+ var indexDef = Builders.IndexKeys.Ascending("States.Key");
+ collection.Indexes.CreateOne(new CreateIndexModel(indexDef));
+ }
+ return collection;
+ }
+
private IMongoCollection CreateAgentTaskIndex()
{
var collection = Database.GetCollection($"{_collectionPrefix}_AgentTasks");
@@ -93,7 +106,7 @@ public class MongoDbContext
=> Database.GetCollection($"{_collectionPrefix}_ConversationDialogs");
public IMongoCollection ConversationStates
- => Database.GetCollection($"{_collectionPrefix}_ConversationStates");
+ => CreateConversationStateIndex();
public IMongoCollection ExectionLogs
=> Database.GetCollection($"{_collectionPrefix}_ExecutionLogs");
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs
index bed3a255..88163b60 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs
@@ -1,5 +1,9 @@
+using Amazon.Util.Internal;
using BotSharp.Abstraction.Conversations.Models;
using BotSharp.Abstraction.Repositories.Filters;
+using MongoDB.Bson.Serialization;
+using MongoDB.Driver;
+using System.Collections.Immutable;
namespace BotSharp.Plugin.MongoStorage.Repository;
@@ -225,91 +229,77 @@ public partial class MongoRepository
public PagedItems GetConversations(ConversationFilter filter)
{
- var conversations = new List();
- var builder = Builders.Filter;
- var filters = new List>() { builder.Empty };
+ var convBuilder = Builders.Filter;
+ var convFilters = new List>() { convBuilder.Empty };
+ // Filter conversations
if (!string.IsNullOrEmpty(filter?.Id))
{
- filters.Add(builder.Eq(x => x.Id, filter.Id));
+ convFilters.Add(convBuilder.Eq(x => x.Id, filter.Id));
}
if (!string.IsNullOrEmpty(filter?.AgentId))
{
- filters.Add(builder.Eq(x => x.AgentId, filter.AgentId));
+ convFilters.Add(convBuilder.Eq(x => x.AgentId, filter.AgentId));
}
if (!string.IsNullOrEmpty(filter?.Status))
{
- filters.Add(builder.Eq(x => x.Status, filter.Status));
+ convFilters.Add(convBuilder.Eq(x => x.Status, filter.Status));
}
if (!string.IsNullOrEmpty(filter?.Channel))
{
- filters.Add(builder.Eq(x => x.Channel, filter.Channel));
+ convFilters.Add(convBuilder.Eq(x => x.Channel, filter.Channel));
}
if (!string.IsNullOrEmpty(filter?.UserId))
{
- filters.Add(builder.Eq(x => x.UserId, filter.UserId));
+ convFilters.Add(convBuilder.Eq(x => x.UserId, filter.UserId));
}
if (!string.IsNullOrEmpty(filter?.TaskId))
{
- filters.Add(builder.Eq(x => x.TaskId, filter.TaskId));
+ convFilters.Add(convBuilder.Eq(x => x.TaskId, filter.TaskId));
}
if (filter?.StartTime != null)
{
- filters.Add(builder.Gte(x => x.CreatedTime, filter.StartTime.Value));
+ convFilters.Add(convBuilder.Gte(x => x.CreatedTime, filter.StartTime.Value));
}
- // Check states
- if (filter != null && !filter.States.IsNullOrEmpty())
+ // Filter states
+ var stateFilters = new List>();
+ if (filter != null && string.IsNullOrEmpty(filter.Id) && !filter.States.IsNullOrEmpty())
{
- var targetConvIds = new List();
-
foreach (var pair in filter.States)
{
- if (pair == null || string.IsNullOrWhiteSpace(pair.Key)) continue;
-
- var query = _dc.ConversationStates.AsQueryable();
- var convIds = query.AsEnumerable().Where(x =>
+ var elementFilters = new List> { Builders.Filter.Eq(x => x.Key, pair.Key) };
+ if (!string.IsNullOrEmpty(pair.Value))
{
- var foundState = x.States.FirstOrDefault(s => s.Key.IsEqualTo(pair.Key));
- if (foundState == null) return false;
-
- if (!string.IsNullOrWhiteSpace(pair.Value))
- {
- return pair.Value.IsEqualTo(foundState.Values.LastOrDefault()?.Data);
- }
-
- return true;
- }).Select(x => x.ConversationId).ToList();
-
- targetConvIds = targetConvIds.Concat(convIds).Distinct().ToList();
+ elementFilters.Add(Builders.Filter.Eq("Values.Data", pair.Value));
+ }
+ stateFilters.Add(Builders.Filter.ElemMatch(x => x.States, Builders.Filter.And(elementFilters)));
}
- filters.Add(builder.In(x => x.Id, targetConvIds));
+ var targetConvIds = _dc.ConversationStates.Find(Builders.Filter.And(stateFilters)).ToEnumerable().Select(x => x.ConversationId).Distinct().ToList();
+ convFilters.Add(convBuilder.In(x => x.Id, targetConvIds));
}
- var filterDef = builder.And(filters);
+ // Sort and paginate
+ var filterDef = convBuilder.And(convFilters);
var sortDef = Builders.Sort.Descending(x => x.CreatedTime);
var pager = filter?.Pager ?? new Pagination();
var conversationDocs = _dc.Conversations.Find(filterDef).Sort(sortDef).Skip(pager.Offset).Limit(pager.Size).ToList();
var count = _dc.Conversations.CountDocuments(filterDef);
- foreach (var conv in conversationDocs)
+ var conversations = conversationDocs.Select(x => new Conversation
{
- var convId = conv.Id.ToString();
- conversations.Add(new Conversation
- {
- Id = convId,
- AgentId = conv.AgentId.ToString(),
- UserId = conv.UserId.ToString(),
- TaskId = conv.TaskId,
- Title = conv.Title,
- Channel = conv.Channel,
- Status = conv.Status,
- DialogCount = conv.DialogCount,
- CreatedTime = conv.CreatedTime,
- UpdatedTime = conv.UpdatedTime
- });
- }
+ Id = x.Id.ToString(),
+ AgentId = x.AgentId.ToString(),
+ UserId = x.UserId.ToString(),
+ TaskId = x.TaskId,
+ Title = x.Title,
+ Channel = x.Channel,
+ Status = x.Status,
+ DialogCount = x.DialogCount,
+ CreatedTime = x.CreatedTime,
+ UpdatedTime = x.UpdatedTime
+ }).ToList();
return new PagedItems
{