Buckyx55
Buckyx55

Reputation: 504

Find Mongoose Document and then Sort Randomly with Different Tiers?

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

Answers (4)

aneroid
aneroid

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" }
])

Mongo Playground

Upvotes: 0

mahdi Ettehadnejad
mahdi Ettehadnejad

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

adel parsa
adel parsa

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

mickl
mickl

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

Related Questions