Use Parse.Query.or with an array of queries

Hello there, I’m running into a pretty weird case which has gotten my head spinning lately. Here’s the scenario: I’m creating a chat application, and when the user opens the app, I want to update the messages he’s missed when offline for each room. So I created this cloud function and here’s the request data: a javascript object, with roomIds as the keys and last updated date for that room as the value. like :

{
   21: Sun Jan 21 2024 10:36:16 GMT+0330 (Iran Standard Time),
   41: Sun Jan 21 2024 10:51:28 GMT+0330 (Iran Standard Time)
}

and I’m willing to process data like this as a cloud function :


Parse.Cloud.define("missedMessages", async (request) => {
        let  result = {};

        const data = request.params;
        const queries = [];

        async function calculate() {
                Object.keys(data).map(async (room) => {
                        const query = new Parse.Query("messages");
                        query.fullText('roomId', room);

                        if (data[room]) {
                                const date = new Date(data[room]);
                                var utc = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(),
                                        date.getUTCDate(), date.getUTCHours(),
                                        date.getUTCMinutes(), date.getUTCSeconds());

                                query.greaterThan('createdAt', new Date(utc));
                        }

                        const response = await query.find();
                        result[room] = response;
                        //queries.push(query);
                })

     }

//      const finalQuery = Parse.Query.or(queries);
//      const result = await finalQuery.find();
//      await calculate();
        return result;
});

The current code simply returns an empty object {}. So I suspected the problem might be related to querying each data individually - all those async and await. As you can see in commented code, I removed calculate wrapper function and synchronized the function passed to map, pushed queries in an array queries, so then I can stack them up in one single query through Parse.Query.or. But apparently it doesn’t work(Throws this error : A ParseQuery must be constructed with a ParseObject or class name.), though the queries array is constructed correctly.

So to sum it up, I go with a few questions.

  1. Can I stack an array of queries in cloud code, instead of this Parse.Query.or(query1, query2, ...)

  2. It seems like the calculate async wrapper function is skipped, despite the await operator. Is it possible to define and call another function inside a cloud code function?

  3. And finally, any thoughts on what’s going on?! Or basically a better practice than I mentioned for the task(perhaps a query shortcut or something?)

Thank you all.

UPDATE :
I also tried Parse.Query.or(...queries). Must answer my first question but still returns an error : Server 500 Uncaught (in promise) Error: [object Object] and the response looks like this {"code":1,"error":{"ok":0,"code":2,"codeName":"BadValue"}}

UPDATE :
This sounds like a bug. Because every query is fine individually and will return desired data. But

await Parse.Query.or(...queries).find();

returns the following error, which apparently has got something to do with mongodb.
{"code":1,"error":{"ok":0,"code":2,"codeName":"BadValue"}}

Instead of dealing with dateTimes you can use simple boolean field.
For ex. if user opens the msgBox - > You can set the seem field is true.

After doing this. Users when login or online again you can fetch new messages by this field.

And you can notify the users with liveQuery, by read seem field if false

Thanks for the advice!
I don’t believe that’s exactly my case. Because messages must be available across devices. Anyways, it had got nothing to do with the dates. The problem is, the query is quiet complicated. You just don’t stack some roomId and date(or boolean) queries. Two factors needs to be checked for each entry which one of them(the date) varies regarding to the first one(id of room). I don’t believe it’s doable with parse SDK, perhaps some lower level MongoDB query is required.

Anyway, for anyone curious, I managed to do it using Promise.all, completing queries sequentially.

I still look forward to anyone who can come up with an actual query for such thing.

You should create every query on same Class - in other words collection.

For example if you try like this :

new Parse.Query(A)
new Parse.Query(B)

You cant use Parse.Query.or

If you want to use query with different class or collection. You should write own parse server or function:

const or = async(options,...queries)=>
   /*: RequestOptions*/ /*: ParseQuery*/
  /*:  ParseQuerySelect*/
{
    const findOptions = {};
    let data = [];
    let pipelines=[];
    if (options.hasOwnProperty('useMasterKey')) {
        findOptions.useMasterKey = options.useMasterKey;
    }
    if (options.hasOwnProperty('sessionToken')) {
        findOptions.sessionToken = options.sessionToken;
    }
    if (options.hasOwnProperty('selectOptions')) {
        const defaultConstraints=options.selectOptions.reduce((acc,cur)=>({...acc,[cur]:1}),{_id:0});
        pipelines.push({project:defaultConstraints});
    }
    for (const query of queries) {
        const className = query.className;
        const result = await query.aggregate(pipelines, findOptions);
        result.forEach(item=>item.className=className);
        result[0]?data.push(...result):null;
        pipelines.shift();
    }
    return data;
}

module.exports = { or };

After you can use or functions like this :

//If you want to select any field
const selects=['message','username',"_id"];
const query = new Parse.Query('A');
const query1 = new Parse.Query('B');
const query2 = new Parse.Query('C');
// send compound query
const data = await or({'useMasterKey':true,'selectOptions':selects},query, query1, query2);

I only recommend the previous answer my opinion for easy management msg management, But this way support your problems.