In my front-end react.js application use to filter and sort data fetching from mongoDB database. I want to move this logic into back-end mongoose query. how can I achieve this? I tried to refactor the code as below but it's making some errors in my code editor.
"error": "MongoServerError: Invalid $addFields :: caused by :: Unrecognized expression '$con'"
Front-end filter and sort
try {
const { data } = await getMobilePosts(skip);
const filterData = await data?.filter(obj => obj.adPromote == "free-ad" || obj.adPromote == "reach-up-ad")
.sort((f,p)=>{
if (f.adPromote === 'reach-up-ad' && p.adPromote !== 'reach-up-ad') {
return -1;
} else if (f.adPromote !== 'reach-up-ad' && f.adPromote === 'reach-up-ad') {
return 1;
}
return 0;
})
.map(obj => {
return {
...obj,
title: `${obj.title} (${obj.features.condition})`
}
});
setPost([...post, ...filterData]);
setSkip(filterData.length);
} catch (err) {
console.log(err)
}
back-end query that tried so far.
Post.aggregate([
{
$match: {
$and: [
{
expiredAt: {$gte: currentDate}
},
{
"status": "live"
}
]
}
},
{
"$addFields": {
"adpromoTypes": {
"$con": {
"if": {
"$and": {
"adPromote": {
"$eq": 'reach-up-ad'
},
}
}
}
}
}
},
{
$sort: {
"_id": -1,
"adpromoTypes": -1
}
},
{
"$skip": skip
},
{
"$limit": PER_REQUEST
},
{
$project: {
"title": 1,
}
}
]);
I have mongoDB collection with below fields:
POST document
I want to filter 'reach-up' ads on the top of the list and then after display 'free-ad'
ex:
- reach up ad
- reach up ad
- free ad
.........
SKIP & LIMIT
skip and limit ads should work like this. When loading ads at the first time I want to show only 5 ads (limit 5). In this 5 ads I want to show if available 'reach-up-ad'. Next I want to skip 5 ads that already loaded. In this set of ad if available again I want to show another 'reach-up-ad'. After that I want to load 'free-ad' continuously but 5 at a time.
thanks to your update i worked on a solution.
You can check it on mongoplayground.
Here is my code with comments in it:
db.collection.aggregate([
{
//match documents not expired
//with "live" status
//where adPromote in ['reach-up-ad', 'free-ad'] to remove 'urgent-ad'
$match: {
$and: [
{
expiredAt: {
$gte: ISODate("2023-08-04T12:02:50.000Z")
}
},
{
"status": "live"
},
{
adPromote: {
$in: [
"reach-up-ad",
"free-ad"
]
}
}
]
}
},
{
$addFields: {
// add a "prioritySort" field to allow custom sort according the value of "adPromote" field
prioritySort: {
$switch: {
branches: [
{
case: {
$eq: [
"$adPromote",
"reach-up-ad"
]
},
then: 3
},
{
case: {
$eq: [
"$adPromote",
"free-ad"
]
},
then: 2
},
{
case: {
$eq: [
"$adPromote",
"urgent-ad"
]
},
then: 1
}
],
default: 0
}
},
//add other custom field here
//coolTitle: {$concat: ["$title"," is a cool title"]}
}
},
// sort by prioritySort field added
// sort then by _id to keep same order and have consistent result
{
$sort: {
prioritySort: -1,
_id: 1
}
},
// skip 1 value
{
$skip: 1
},
// take the 3 next
{
$limit: 3
},
//optional remove added fields with unset
{
$unset: [
"prioritySort",
// "coolTitle"
]
}
])
Make sure to change expiredDate
, skip
and limit
values by your values. Change also db.collection
by Posts
to make it work.
I wasn't sure if you wanted to keep other type of ads so i made a filter to keep only 'reach-up-ad' and 'free-ad'. You can remove this part if it doesn't apply to your issue.
Hope that helps. Ask me any question if it doesn't !
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments