Reputation: 504
I currently have a .find() associated with documents in a collection, and it's currently sorting the document based on their "status" and sorting them by their most recent. Is it possible to sort them by the status first, and then randomly sort those within their respective tiers?
For instance if I have users that are three tiers: Tier 1, Tier 2, and Tier 3. Currently, it's sorting by Tier 1's (most recently), then Tier 2's (most recently), then Tier 3's (most recently). I'd like it to instead sort like: Tier 1's (random), Tier 2's (random), Tier 3's (random). But still display the results like so: Tier 1, Tier 2, then Tier 3. Is this possible?
router.get('/users', (req, res) => {
const errors = {};
Users.find().sort({tierStatus: -1, tierStatus: -1, tierStatus: -1})
.then(users => {
if (!users) {
errors.nousers = 'There are no users';
return res.status(404).json(errors);
}
res.json(users);
})
.catch(err => res.status(404).json({
nousers: 'There are no users'
}));
});
Upvotes: 1
Views: 2770
Reputation: 15987
With MongoDB 4.4.2 & 5.0 onwards, you can do this with $rand
.
With an aggregation, you can use it for sort on tierStatus
descending + rand
ascending, and then unset:
db.collection.aggregate([
{ $match: {} }, // your find clauses go here, if any
{ $set: { rand: { $rand: {} } } },
{ $sort: { tierStatus: -1, rand: 1 } },
{ $unset: "rand" }
])
Upvotes: 0
Reputation: 1
You can use these custom functions to return items in random order by also defining seed. :
export function xorshift(seed: number): any {
let x = seed
return function (): number {
x ^= x << 13
x ^= x >> 17
x ^= x << 5
return Math.abs(x) / 0xffffffff
}
}
export function shuffleArray(array: any[], randomFunc: () => number): any {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(randomFunc() * (i + 1))
;[array[i], array[j]] = [array[j], array[i]]
}
return array
}
const query = PropertyModel.find({ status: 2 })
filteredProperties = await query.exec()
const randomFunc = xorshift(20)
filteredProperties = shuffleArray(filteredProperties, randomFunc)
Upvotes: 0
Reputation: 446
you can use $sample sort operator in mongoose aggregation for example I'd like select 6 random blogs:
const randomBlogs = await blogs.aggregate([
{ $sample: { size: 6 } },
]);
Upvotes: 0
Reputation: 49955
Currently there's no way to generate a random value in MongoDB thus you cannot sort "randomly". The only operator you can consider is $sample which picks random documents but you cannot use it along with sort()
or $sort
The only solution is to sort by deterministic field and then shuffle in your application logic.
Upvotes: 1