🕵️ refactor: Optimize Message Search Performance (#9818)

* 🕵️ feat: Enhance Index Sync and MeiliSearch filtering for User Field

- Implemented `ensureFilterableAttributes` function to configure MeiliSearch indexes for messages and conversations to filter by user.
- Updated sync logic to trigger a full re-sync if the user field is missing or index settings are modified.
- Adjusted search queries in Conversation and Message models to include user filtering.
- Ensured 'user' field is marked as filterable in MongoDB schema for both messages and conversations.

This update improves data integrity and search capabilities by ensuring user-related data is properly indexed and retrievable.

* fix: message processing in Search component to use linear list and not tree

* feat: Implement user filtering in MeiliSearch for shared links

* refactor: Optimize message search retrieval by batching database calls

* chore: Update MeiliSearch parameters type to use SearchParams for improved type safety
This commit is contained in:
Danny Avila 2025-09-24 16:27:34 -04:00 committed by GitHub
parent f9aebeba92
commit 57f8b333bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 263 additions and 31 deletions

View file

@ -3,8 +3,8 @@ const { logger } = require('@librechat/data-schemas');
const { ContentTypes } = require('librechat-data-provider');
const {
saveConvo,
saveMessage,
getMessage,
saveMessage,
getMessages,
updateMessage,
deleteMessages,
@ -58,34 +58,51 @@ router.get('/', async (req, res) => {
const nextCursor = messages.length > pageSize ? messages.pop()[sortField] : null;
response = { messages, nextCursor };
} else if (search) {
const searchResults = await Message.meiliSearch(search, undefined, true);
const searchResults = await Message.meiliSearch(search, { filter: `user = "${user}"` }, true);
const messages = searchResults.hits || [];
const result = await getConvosQueried(req.user.id, messages, cursor);
const activeMessages = [];
const messageIds = [];
const cleanedMessages = [];
for (let i = 0; i < messages.length; i++) {
let message = messages[i];
if (message.conversationId.includes('--')) {
message.conversationId = cleanUpPrimaryKeyValue(message.conversationId);
}
if (result.convoMap[message.conversationId]) {
const convo = result.convoMap[message.conversationId];
const dbMessage = await getMessage({ user, messageId: message.messageId });
activeMessages.push({
...message,
title: convo.title,
conversationId: message.conversationId,
model: convo.model,
isCreatedByUser: dbMessage?.isCreatedByUser,
endpoint: dbMessage?.endpoint,
iconURL: dbMessage?.iconURL,
});
messageIds.push(message.messageId);
cleanedMessages.push(message);
}
}
const dbMessages = await getMessages({
user,
messageId: { $in: messageIds },
});
const dbMessageMap = {};
for (const dbMessage of dbMessages) {
dbMessageMap[dbMessage.messageId] = dbMessage;
}
const activeMessages = [];
for (const message of cleanedMessages) {
const convo = result.convoMap[message.conversationId];
const dbMessage = dbMessageMap[message.messageId];
activeMessages.push({
...message,
title: convo.title,
conversationId: message.conversationId,
model: convo.model,
isCreatedByUser: dbMessage?.isCreatedByUser,
endpoint: dbMessage?.endpoint,
iconURL: dbMessage?.iconURL,
});
}
response = { messages: activeMessages, nextCursor: null };
} else {
response = { messages: [], nextCursor: null };