feat: add MongoDB search method, endpoints, and settings module
deploy-chabokan / deploy (push) Canceled after 0s

This commit is contained in:
2026-08-19 05:50:14 +03:30
parent 3829851566
commit acb2e5d623
18 changed files with 649 additions and 21 deletions
@@ -2,7 +2,7 @@ const catchAsync = require('../../globalErrorHandler/catchAsync')
const transactionService = require('./transactionService')
exports.searchTransactions = catchAsync(async (req, res, next) => {
const { facets, transactions, totalCount, pagesCount } = await transactionService.searchTransactions(req.query)
const { facets, transactions, totalCount, pagesCount, searchEngine } = await transactionService.searchTransactions(req.query)
res.status(200).json({
status: 'success',
@@ -10,9 +10,24 @@ exports.searchTransactions = catchAsync(async (req, res, next) => {
transactions,
totalCount,
pagesCount,
searchEngine,
})
})
exports.searchTransactionsMongo = catchAsync(async (req, res, next) => {
const { facets, transactions, totalCount, pagesCount, searchEngine } = await transactionService.searchTransactionsMongo(req.query)
res.status(200).json({
status: 'success',
facets,
transactions,
totalCount,
pagesCount,
searchEngine: searchEngine || 'mongo',
})
})
exports.indexAllTransactions = catchAsync(async (req, res, next) => {
const { indexedCount } = await transactionService.indexAllTransactions()
@@ -31,6 +31,13 @@ router.get(
transactionController.searchTransactions
)
router.get(
'/admin/search-mongo',
// perm.requires('getallbelongings'),
transactionController.searchTransactionsMongo
)
router.get(
'/admin/get-stock-by-belonging/:belongingId',
// perm.requires('getallbelongings'),
+108 -5
View File
@@ -165,15 +165,116 @@ const ensureCollectionExists = async (forceRecreate = false) => {
}
}
const settingService = require('../setting/settingService')
const searchTransactionsMongo = async (inputQuery = {}) => {
const page = parseInt(inputQuery.page) || 1
const per_page = parseInt(inputQuery.per_page) || parseInt(inputQuery.limit) || 20
const mongoQuery = {}
const q = (inputQuery.query || inputQuery.search || inputQuery.q || '').trim()
if (q && q !== '*') {
const searchRegex = { $regex: q, $options: 'i' }
const orConditions = [
{ description: searchRegex },
{ userName: searchRegex },
{ type: searchRegex },
{ status: searchRegex },
{ source: searchRegex },
]
if (mongoose.Types.ObjectId.isValid(q)) {
orConditions.push({ _id: q })
orConditions.push({ propertyId: q })
orConditions.push({ userId: q })
}
mongoQuery.$or = orConditions
}
if (inputQuery.type) mongoQuery.type = inputQuery.type
if (inputQuery.status) mongoQuery.status = inputQuery.status
if (inputQuery.source) mongoQuery.source = inputQuery.source
if (inputQuery.propertyId && mongoose.Types.ObjectId.isValid(inputQuery.propertyId)) {
mongoQuery.propertyId = inputQuery.propertyId
}
if (inputQuery.userId && mongoose.Types.ObjectId.isValid(inputQuery.userId)) {
mongoQuery.userId = inputQuery.userId
}
let sortObj = { createdAt: -1 }
if (inputQuery.sort) {
if (typeof inputQuery.sort === 'string') {
const parts = inputQuery.sort.split(':')
const field = parts[0]
const order = parts[1] === 'asc' ? 1 : -1
sortObj = { [field]: order }
} else if (typeof inputQuery.sort === 'object') {
sortObj = inputQuery.sort
}
}
const totalCount = await Transaction.countDocuments(mongoQuery)
const transactions = await Transaction.find(mongoQuery)
.populate('propertyId')
.populate('userId')
.sort(sortObj)
.skip((page - 1) * per_page)
.limit(per_page)
const items = transactions.map((t) => {
return {
_id: t._id.toString(),
id: t._id.toString(),
type: t.type || '',
status: t.status || '',
source: t.source || '',
value: t.value || 0,
description: t.description || '',
createdAt: Math.floor(new Date(t.createdAt || t.date || Date.now()).getTime() / 1000),
date: t.date,
belongingName: t.propertyId?.name || '',
belongingId: t.propertyId?._id ? t.propertyId._id.toString() : '',
propertyId: t.propertyId,
userName: t.userName || t.userId?.name || '',
userId: t.userId,
}
})
const pagesCount = Math.ceil(totalCount / per_page) || 1
return {
facets: [],
transactions: items,
totalCount,
pagesCount,
searchEngine: 'mongo',
}
}
const searchTransactions = async (inputQuery) => {
await ensureCollectionExists(false)
inputQuery = updateInputQuery(inputQuery, {})
try {
const setting = await settingService.getSearchSettingByPage('transactions')
if (setting && setting.searchMethod === 'mongo') {
return searchTransactionsMongo(inputQuery)
}
} catch (e) {
console.warn('Failed to fetch search setting for transactions, attempting typesense:', e.message)
}
const tsFeatures = new TsApiFeatures(client, 'transactions', inputQuery).filter().facet().sort().limitFields().paginate().search()
try {
await ensureCollectionExists(false)
const updatedQuery = updateInputQuery({ ...inputQuery }, {})
let { facets, items, totalCount, pagesCount } = await tsFeatures.execute()
const tsFeatures = new TsApiFeatures(client, 'transactions', updatedQuery).filter().facet().sort().limitFields().paginate().search()
return { facets, transactions: items, totalCount, pagesCount }
let { facets, items, totalCount, pagesCount } = await tsFeatures.execute()
return { facets, transactions: items, totalCount, pagesCount, searchEngine: 'typesense' }
} catch (err) {
console.warn('Typesense search failed for transactions, falling back to MongoDB:', err.message)
return searchTransactionsMongo(inputQuery)
}
}
const updateInputQuery = (inputQuery, extraQueries) => {
@@ -257,4 +358,6 @@ module.exports = {
getTransactionByBelongingId,
indexAllTransactions,
searchTransactions,
searchTransactionsMongo,
}