Query an array of objects

Hi guys,

I am trying to write a query that looks like this:

Moralis.Cloud.define("fetchMyVotes", async(request) => {
	const query = new Moralis.Query("myObjects");
  const pipeline = [
    { match: { voters.voter: request.user.id } }
  ];
  
  return await query.aggregate(pipeline);
});

This does not work an throws with the error “Invalid Function”.

myObjects table has a column called voters containing an array of objects like this:

[{“voter”: “user1”, “someValue”: 50}, {“voter”: “user2”, “someValue”: 89}, …]

How can I query for the voter property from within a cloud function?

1 Like

Hi @Thomas

If your you want to get info from a specific object try using this:

Moralis.Cloud.define("fetchMyVotes", async(request) => {
  const objectId = "8AiPsNBBcYXPIDkdgJp8QMv4"; //input your value here
  const query = new Moralis.Query("MyObjects");
  
  query.equalTo("objectId", objectId);
  const queryResult = await query.first({ useMasterKey: true });
  const voters = queryResult.get("voters");

  let values = [];
  voters.forEach((element) => {
    values.push(element.someValue);
  });
  
  return values;
});

That function returns an array with values of the voters. I made the code in detail for your better understanding.

Hope this helps. :slight_smile:

2 Likes

Hi @Yomoo,
thanks for the reply. Querying an object is not exactly what is my problem here, a simple query works just fine. What I am trying to achieve is querying a value of a property of an object inside an array.

So I have a field called voters. This field holds an array of objects. Each object holds two properties. My question is: how can I query for only one property instead of the whole object?

1 Like

I’ve changed the function for getting property “someValue”

Moralis.Cloud.define("fetchMyVotes", async(request) => {
  const { userId } = request.params;
  const objectId = "8AiPsNBBcYXPIDkdgJp8QMv4";
  const query = new Moralis.Query("MyObjects");
  
  query.equalTo("objectId", objectId);
  const queryResult = await query.first({ useMasterKey: true });
  const voters = queryResult.get("voters");
  
  const voter = voters.find((obj) => obj.voter == userId);
  const value = voter.someValue;
  return value;
});
1 Like

Hmm…
thank you for taking time @Yomoo,
This is still not what I am trying to achieve. I am sorry to bug you again with this.
I don’t want to hardcode the objectId, but I want to query for all objects in the table and only return the ones that hold the currentuser id inside the voters array of objects.


Maybe this pic helps to illustrate? The voters field holds an array of objects, each object has a voter and timestamp property.
I want to return posts that hold the current user id as voter inside the voters field.

:thinking:

Ok, I found another solution which is working. I will leave it here for future readers:

 let posts = await Moralis.Cloud.run("fetchAllPosts");
          console.log("ALLPOSTS", posts);
          const filteredPosts = posts.filter((post) => {
            return post.voters.find(
              (currentVoter) => currentVoter.voter === currentUser.id
            );
          });
          console.log("FILTERS", filteredPosts);

So this is only fetching all posts via a cloud function and then utilizing the power of good old plain JS to filter out all posts that hold the current user as a voter.

Still, I would be interested to know if this could work with just cloud functions?

Hey @Thomas

Awesome work :muscle:. I’m already prepairing the code to use cloud functions only. :slightly_smiling_face:

1 Like

Please clarify. Do you want to return the entire object with the required data? Or just the specific meaning of the object for example memeName or description?

I want to return the entire object

1 Like

Thank you for your patience :grinning:

If I understood correctly the way you store rows in MyObjects this solution will work correctly.

Moralis.Cloud.define("fetchMyVotes", async(request) => {
  const { userId } = request.params;
  const query = new Moralis.Query("MyObjects");
  const results = await query.find();

  const post = results.filter((obj) => obj.voters.find((o) => o.voter == userId));
  return post;
});

I will wait for your feedback :wink:

1 Like

Hey @Thomas :wink:

I’ve changed the function a little. If previous version didn’t work correctly, try this:

Moralis.Cloud.define("fetchMyVotes", async(request) => {
  const { userId } = request.params;
  const query = new Moralis.Query("MyObjects");
  
  const results = await query.find();
  const res = JSON.stringify(results);
  const post = JSON.parse(res).filter((obj) => obj.voters.find((o) => o.voter == userId));
  return post;
});

It works with database like this:

1 Like

Thank you so much @Yomoo for looking into this with me. I will test these scripts as soon as possible and let you know!
Can I use all JavaScript methods inside the cloud functions? map, filter, includes, sort … and so on?

Sure, cloud functions are in JS, so you can easily use these methods :wink:

Have you already tested the code?

How can this be resolved in case of voters being an array of pointers?

I’m having a hard time to get the actual data instead of pointers.

you mean that you get the pointers but you don’t get the data where those pointers point too?

in that case you could do an additional query, or try to use query.include and query.select

you can also try to search on google how it could be done for parse server, Moralis Server uses parse server

Exactly, I’m missing the data. I get

ParseObjectSubclass {
  className: 'SomeOtherCollection',
  _objCount: 3066,
  id: 'a1yyBsQWP2cGLIfv6JwSBX27'
}

I tried including the collection that is referenced.

For example:

const SomeNewCollection = Moralis.Object.extend("SomeNewCollection");
const SomeOtherCollection = Moralis.Object.extend("SomeOtherCollection");
const entries = new Array<SomeOtherCollection>()
const entry = new SomeOtherCollection()
entry.set("myAttribute", 2)
entries.push(entry)
newCollection.setAttribute("pointerList", entries)

// Query
const query = new Moralis.Query(SomeNewCollection);
// Tried: query.select("pointerList.myAttribute")
// Tried: query.include("SomeOtherCollection")
const results = await query.find({useMasterKey: true})

Are you referring to this parse-server: https://github.com/parse-community/parse-server

I am referring to that parse server

1 Like

I can’t really find a suitable API entry for my problem in parse-server.

Is my usage of select and include correct?

is it as mentioned above select("pointerList.myAttribute") if pointerList is an Array?

=>

=>

        const query = new Parse.Query('AContainer');
        query.include('objects');
        return query.find();
1 Like

Feel hugged for your fast support. Live saver.

(Edit: It was the missing query.include("queryList") as you pointed out!)