Any way to limit included objects?

I am querying a class that has relations to other classes as arrays.

I know I can use .include() to have my query on the base class include the array objects for each object.

But I want to optimize for speed and limit the related objects that can be quite many to only the last five or so. Can this be done?

if you have many objects you should use a relation instead of saving the objects in an array.

If relations you can then query and apply constrains.

Thank you for this suggestion. My understanding is that relations are recommended for 100+ objects, and that they can not be included in the main query, but must always be fetched with a new query? I would have liked to have the simplicity of the array and automatic inclusion, but I think the payload will be too large if all array items are fetched without limits. So maybe I need to go for a relation.

You could use beforeSave to create a new column with only the 5 latest objects, then in your query only include those objects.

Parse.Cloud.beforeSave("ClassName", ({object}) => {
  if (object.dirty('pointers') {
    const array = object.get('pointers') || [];
    while (array.length > 5) {
      array.shift();
    }
    object.set('recentPointers', array);
   // now change to query.include('recentPointers') 
});

Thank you! This is a great solution that I will implement. I guess if I want to keep the the full list of all objects it can be another class with relations as mentioned above.

You don’t need a nother class. You can think of relations as a sql join table. This means you can have all your related objects stored via relations, but still do what @dblythy mentioned.

This way, you still have all your data accssible if you/when you need it, but you hav a nice quick way to access your latest objects.

Yeah, if you are saving many pointers a better approach could be:

const obj = new Parse.Object("TestObject");
const relationObj = new Parse.Object("TestObject");
await relationObj.save();
const relation = obj.get("relation");
relation.add(relationObj);
await obj.save();

Parse.Cloud.afterFind("TestObject", async ({objects, user})  => {
  return await Promise.all(objects.map(async object => {
     const last5 = await object.relation("relation").query().descending("createdAt").limit(5).find({sessionToken: user?.getSessionToken()});
     object.set("recentPointers", last5);
     return object;
  });
});

Thank you! That last one made my day! It solves this problem beautifully, and it is also a pattern that I can reuse for other similar issues. I didn’t quite get why obj and relationObj were set to instances of the same class, but I guess one is the main class and the other is the relation class. My context is that I am saving a history of completions for repeating tasks. This will mostly be few items, but for tasks that repeat frequently it can become a long list over time, and then relations is better than arrays. So, great solution!

I thought I would share the working code I ended up using. Hope this can help others. This can be useful for logging any kind of activity and have a shortlist handy.

Parse.Cloud.beforeSave("Task", async function(request, response) {

    /* Conditions and other stuff here */
 
    const task = request.object
    const historyItem = new Parse.Object('History')
    historyItem.set('doneDate', new Date()) 
    historyItem.set('task',  task.toPointer())
    historyItem.set('owner', task.get('owner'))
    await historyItem.save(null, {useMasterKey: true })

    task.relation('history').add(historyItem)

    //Make sure shortlist contains max 5 items
    const array = task.get('recentHistory') || []
    array.push(historyItem)
    task.set('recentHistory', array.slice(0,5))
})

Please do comment if I made any SNAFUs or misunderstood something important from the comments above.

Should have been array.unshift, not push, then it works.