timetosmile
timetosmile

Reputation: 73

How can I get all Objects from parse server by an array of objectIDs?

my second question relates to my first question. The answer just help me to understand my problem a little bit more.

My situation:

I have a table in parseplattform which stores my user pics. The user should be able to delete the selected ones. So I make a checkbox under each pic which gives me back the picID. So the next step is to finde all the selected pics in my table and "destroy" them.

This is my code snippit for just finding the selected pics:

  var inputs = document.querySelectorAll("input[type='checkbox']");

  for(var i = 0; i < inputs.length; i++) {
    if(inputs[i].checked == true){
      var imgForDelPromise = new Promise(function (resolve) {
        userPics_query.get(inputs[i].id, {
          success: function(picForDelete) {
            alert(picForDelete.id);
            resolve(picForDelete);
           },
           error: function(picForDelete, error) {
             alert("Error: " + error.code + " " + error.message);
           }
         });
      });
    }
  }

My problem:

If I select out of 12 pics, pic No. 1, 5 and 8 I would expect that I also will get back the ID of pic 1, 5 and 8 BUT I allways get the last one as often as many items I had selected. In this example 3 times 8.

Like in my first question suggested I tried it with promises but it didn't helped.

So I asked google and got this but it also didn't helped me.

I hope you understand my question and problem and hope you can help me.

Maybe there is an easier way like query.equalTo() where I can pass an array with different elements and get back an array with different objects. But I couldn't find it yet.

Thank you.

UPDATE:

The problem remains and I try to specify it a little bit more. For example:

var ids = Array.from(document.querySelectorAll("input[type='checkbox']"))
.filter( //only checked inputs
    function(input) { return input.checked; }
).map( //map to a promise
    function(input) {
        return input.id;
    }
);

console.log(ids);

ids.forEach(function(id) {
    userPics_query.get(id)
    .then(function(picObject) {
        console.log(picObject.id);
    })
    .then(function(error) {
        console.log(error);
    });
});

what I tried to build by your answers give me the following log:

Array [ "x2WSASwKWI", "NuhRXja0PL" ]
NuhRXja0PL
NuhRXja0PL

My Problem: I don't know how iterate thru an array and get back for each element the request from the server because every loop comes frist an THEN the get request and I can't get it in the right order. What do I miss?

By using Promise.all(promises) I pass the complete array but query.get can only handle one string at a time!

Update 2:

The function

query.get("xWMyZ4YEGZ", {
  success: function(gameScore) {
    // The object was retrieved successfully.
  },
  error: function(object, error) {
    // The object was not retrieved successfully.
    // error is a Parse.Error with an error code and message.
  }
});

cames from parseplattform.org

Upvotes: 3

Views: 2398

Answers (3)

Alejandro
Alejandro

Reputation: 220

I have seen that the most perform at thing to do is query for all ids in a single query and then manipulate them how you want.

export const getUsers = async (ids: string[]) => {
  const userQuery = new Parse.Query(Parse.User);
  userQuery.containedIn('objectId', ids);

  const data = await userQuery.find({ useMasterKey: true });

  const map = data.reduce((acc, item) => ({
      ...acc,
      [item.id]: item,
  }), {} as { [id: string]: Parse.User });

  return map;
};

Upvotes: 1

danh
danh

Reputation: 62676

There's no need to create a promise, since the query functions return their own promises. In other words, in your code, all of these...

userPics_query.get(someParam, { success : successFn, error : errorFn })

may be replaced by these...

userPics_query.get(someParam).then(successFn, errorFn)

And wherever you've wrapped the first form in a Promise creation, you should definitely delete that and use the second form. In general, build functions for small, testable bits of work.

Applying that to your code, build a function to return a promise to get a user pic given an id...

// note - OP should substitute real collection and prop names
function userPicWithId(inputId) {
    var query = new Parse.Query("MyUserPicCollection");
    query.equalTo("myUserPicIdProperty", inputId);
    return query.get(inputsId);
}

Build a function to return an array of ids from checked checkboxes (idea borrowed from here)...

// something like this, but OP should test
function checkedIds() {
    return $(":checkbox:checked").map(() => this.id).get();
}

That gives us two simple, testable functions. And it's simple to use them as follows...

let promises = checkedIds().map(anId => userPicWithId(anId);

Run all of the promises with Promise.all...

Promise.all(promises).then(results => console.log(results));

All of this advice holds true for your earlier question as well. Once you get the hang of using properly encapsulated promises and logic, things get much simpler.

Upvotes: 2

HMR
HMR

Reputation: 39270

I'm not sure if the code you posted is the actual code giving you the problem. The variable i in your loop should increment as it is not used in an asynchronous callback (function passed to new Promise is immediately executed).

However; the code that does give you the problem could be resolved when you use the inputs as an array, filter out the ones that are not checked and then map them to promises:

var inputs = Array.from(document.querySelectorAll("input[type='checkbox']"));
Promise.all(
  inputs.filter(//only checked inputs
    function(input){return input.checked; }
  ).map(//map to a promise
    function(input){
      console.log("calling get with id:",input.id);
      //removed the new Promise wrap because the get function
      //  returns a promise
      return (new Parse.Query(SomeThing)).get(input.id);
    }
  )
)
.then(
  function(deleted){ console.log("deleted:",deleted); },
  function(error){console.error("something went wrong:",error); }
);

Since the problem obviously comes from userPics_query.get and not provided in the question you could badly solve it by processing the id's one at the time. You could do so by doing the following:

Array.from(document.querySelectorAll("input[type='checkbox']"))
.filter(//only checked inputs
    function(input){return input.checked; }
).reduce(//only start the next if current is finished
  function(p,input){
    console.log("calling get with id:",input.id);
    return p.then(
      all=>
        userPics_query.get(input.id)
        .then(item=>all.concat([item]))
    );
  },
  Promise.resolve([])
)
.then(
  function(deleted){ console.log("deleted:",deleted); },
  function(error){console.error("something went wrong:",error); }
);

It would probably better to keep using Promise.all and try to figure out what's wrong with userPics_query.get, I bet it's shared global mutable dependency that's used in asynchronous code.

Upvotes: 2

Related Questions