0

I need to write beforeDelete function in parse cloud code, with more than one query The following code will delete all comments, but not images

note: Post object has 2 columns (Relation and Relation) Image and Comment are custom classes

e.g.

Parse.Cloud.beforeDelete("Post", function(request, response) {

    // delete all its comments
    const commentsQuery = new Parse.Query("Comment");
    commentsQuery.equalTo("postId", request.object.get("objectId"));
    commentsQuery.find({ useMasterKey: true })
        .then(function(comments) {
            return Parse.Object.destroyAll(comments,{useMasterKey: true});
        })
        .catch(function(error) {
            response.error("Error finding comments line 91 " + error.code + ": " + error.message);
        });

        // delete all its images
        const postQuery = new Parse.Query("Post");
        postQuery.equalTo("postId",  request.object.get("objectId"));
    //  postQuery.include("images");

        postQuery.first({useMasterKey: true})
            .then(function(aPost){
                var images = aPost.relation("images");
                images.query().find({useMasterKey: true}).then(function(foundImages){
                        return Parse.Object.destroyAll(foundImages,{useMasterKey: true});
                    }).catch(function(error){
                        response.error("Error finding images line 107 " + error.code + ": " + error.message);

                    });
            })
            .catch(function(error) {
                console.error("Error finding related comments " + error.code + ": " + error.message);
                response.error("Error finding post line 113 " + error.code + ": " + error.message);
            });

            response.success();
});

Edit

Parse Log

    2018-03-19T00:33:50.491Z - beforeDelete failed for Post for user undefined:
  Input: {"User":{"__type":"Pointer","className":"_User","objectId":"LZXSK7AwE7"},"Content":"","Title":"ios ui, coffee shop app","isPublic":true,"createdAt":"2017-11-23T06:37:55.564Z","updatedAt":"2018-03-19T00:32:30.180Z","views":2,"images":{"__type":"Relation","className":"Image"},"mainColors":{"__type":"Relation","className":"Color"},"Comments":{"__type":"Relation","className":"Comment"},"objectId":"3UDJCIXxGS"}
  Error: {"code":141,"message":"Error finding images line 107 undefined: A promise was resolved even though it had already been resolved."}

How to fix this to succeed in destroying all its images and comments

Hatim
  • 1,516
  • 1
  • 18
  • 30
  • This is the beforeDelete for a "Post" object, but you're doing a query for the Post using its objectId. Do you have a separate Post object that has the Image attached, too? You said Post has 2 columns, both relations, yet you're querying against a postId field. Perhaps that second query was meant to be on a separate object? With promises, they get run on a separate thread while the main thread continues, so here you're always calling `response.success()` before the queries run. You could see relevant errors if you put the queries into an array and use `Parse.Promise.when(queries).then(...` – Jake T. Mar 19 '18 at 21:50
  • @JakeT. no I am doing a Comment query using postId. Could you post the answer please? I didn't understand you – Hatim Mar 20 '18 at 00:41
  • I need to understand your setup. You are doing a Post query. The second one. Under `// delete all its images` What is the object structure? Do you have the right class? – Jake T. Mar 20 '18 at 01:45
  • Also, assuming the images are stored as Parse Files, you can't use `.include()` on a file field. The file will just be its URL, no data. If you need access to the data within a query you would have to iterate over the query results. – Jake T. Mar 20 '18 at 01:47
  • Oh ya... I created the second query (Post) just to include images (Relation) ... Overall, I have a Post class which has images (Relation) . I have another class called Comment which has postId (String). And I have another class called Image which has imageFile (File). – Hatim Mar 20 '18 at 02:03
  • Ahhh. Then perhaps your issue is just that you use `postId` instead of `objectId` in the second query... Try removing the `equalTo` requirement, use `postQuery.get( request.object.id, {useMasterKey})` instead of `postQuery.first...` Also, FYI objects have a `id` property instead of using `.get('objectId')` Also FYI, the images won't be actually deleted from your storage unless you have a beforeDelete handler for your Image class that actually deletes these images. You may or may not want this functionality. Generally you hide the image from the user but save it and references to it. – Jake T. Mar 20 '18 at 02:37

1 Answers1

1

I suggest reorganizing the code into smaller testable, promise returning functions, something like this...

function commentsForPost(postId) {
    const commentsQuery = new Parse.Query("Comment");
    commentsQuery.equalTo("postId", postId);
    return commentsQuery.find({ useMasterKey: true })
}

function destroy(objects) {
    return Parse.Object.destroyAll(objects,{useMasterKey: true});
}

function imagesForPost(post) {
    let images = post.relation("images");
    return images.query().find({useMasterKey: true});
}

Now the beforeDelete function is clear and simple...

Parse.Cloud.beforeDelete("Post", function(request, response) {
    // get the post's comments
    let post = request.object;
    return commentsForPost(post.id)
    .then(comments => destroy(comments))
    .then(() => imagesFromPost(post))
    .then(images => destroy(images))
    .then(() => response.success());
});
danh
  • 62,181
  • 10
  • 95
  • 136