Repository: parse-community/Parse-SDK-JS (JavaScript)

Issue:
toJSON() repeats pending updates to nested keys
### New Issue Checklist
<!--
    Check every following box [x] before submitting your issue.
    Click the "Preview" tab for better readability.
    Thanks for contributing to Parse Platform!
-->

- [x] I am not disclosing a [vulnerability](https://github.com/parse-community/parse-server/blob/master/SECURITY.md).
- [x] I am not just asking a [question](https://github.com/parse-community/.github/blob/master/SUPPORT.md).
- [x] I have searched through [existing issues](https://github.com/parse-community/Parse-SDK-JS/issues?q=is%3Aissue).
- [x] I can reproduce the issue with the latest versions of [Parse Server](https://github.com/parse-community/parse-server/releases) and the [Parse JS SDK](https://github.com/parse-community/Parse-SDK-JS/releases). <!-- We don't investigate issues for outdated releases. -->

### Issue Description
<!-- What is the specific issue? -->
If there are pending updates to nested fields, the object returned by `toJSON()` is corrupted.

### Steps to reproduce
<!-- How can someone else reproduce the issue? -->
```
a = new Parse.Object("MyObject");
a.set('obj', {});
await a.save();
a.set('obj.a', 0);
console.log(a.toJSON());
```

### Actual Outcome
<!-- What outcome, for example query result, did you get? -->
Prints an object with the keys `{obj: {a: 0}, 'obj.a': 0}`

### Expected Outcome
<!-- What outcome, for example query result, did you expect? -->
Should print roughly `{obj: {a: 0}}`
###  Environment
<!-- Be specific with versions, don't use "latest" or semver ranges like "~x.y.z" or "^x.y.z". -->

Server
- Parse Server version: `irrelevant`
- Operating system: `Ubuntu 20.04`
- Local or remote host (AWS, Azure, Google Cloud, Heroku, Digital Ocean, etc): `local`

Database
- System (MongoDB or Postgres): `MongoDB`
- Database version: `5.0.6`
- Local or remote host (MongoDB Atlas, mLab, AWS, Azure, Google Cloud, etc): `local`

Client
- Parse JS SDK version: `alpha (d084ac9be058d9b13f8ac2bbf04615f76dc2800d)`

### Logs
<!-- Include relevant logs here. Turn on additional logging by configuring VERBOSE=1 in your environment. -->



Discussion:

### Thanks for opening this issue!

- 🚀 You can help us to fix this issue faster by opening a pull request with a failing test. See our [Contribution Guide](https://github.com/parse-community/parse-server/blob/master/CONTRIBUTING.md) for how to make a pull request, or read our [New Contributor's Guide](https://blog.parseplatform.org/learn/tutorial/community/nodejs/2021/02/14/How-to-start-contributing-to-Parse-Server.html) if this is your first time contributing.

<!-- parse-issue-bot-meta-tag-id {"suggestPr":true,"thanksFeature":false,"thanksPr":false} -->


Did you mix expected and actual outcome?
Whoops. Fixed.
🎉 This change has been released in version [5.1.0-alpha.8](https://github.com/parse-community/Parse-SDK-JS/releases/tag/5.1.0-alpha.8)
🎉 This change has been released in version [5.1.0-beta.1](https://github.com/parse-community/Parse-SDK-JS/releases/tag/5.1.0-beta.1)
🎉 This change has been released in version [5.1.0](https://github.com/parse-community/Parse-SDK-JS/releases/tag/5.1.0)



Patch:
diff --git a/src/ParseObject.js b/src/ParseObject.js
index 826a2458e..b011ce151 100644
--- a/src/ParseObject.js
+++ b/src/ParseObject.js
@@ -470,10 +470,6 @@ class ParseObject {
         json[attr] = encode(attrs[attr], false, false, seen, offline);
       }
     }
-    const pending = this._getPendingOps();
-    for (const attr in pending[0]) {
-      json[attr] = pending[0][attr].toJSON(offline);
-    }
 
     if (this.id) {
       json.objectId = this.id;


Test patch:
diff --git a/integration/test/ParseObjectTest.js b/integration/test/ParseObjectTest.js
index 8657f1f57..ef3aed26a 100644
--- a/integration/test/ParseObjectTest.js
+++ b/integration/test/ParseObjectTest.js
@@ -292,6 +292,18 @@ describe('Parse Object', () => {
     assert.strictEqual(result.get('a').b.c.d, 2);
   });
 
+  it('can set nested fields without repeating pending operations on toJSON (regression test for #1452)', async () => {
+    const a = new Parse.Object('MyObject');
+    a.set('obj', {});
+    await a.save();
+    a.set('obj.a', 0);
+    const json = a.toJSON();
+    expect(json.obj).toEqual({ a: 0 });
+    expect(new Set(Object.keys(json))).toEqual(
+      new Set(['objectId', 'createdAt', 'updatedAt', 'obj'])
+    );
+  });
+
   it('can increment nested field and retain full object', async () => {
     const obj = new Parse.Object('TestIncrementObject');
     obj.set('objectField', { number: 5, letter: 'a' });
diff --git a/src/__tests__/ParseObject-test.js b/src/__tests__/ParseObject-test.js
index bd6643ff2..890d77ff4 100644
--- a/src/__tests__/ParseObject-test.js
+++ b/src/__tests__/ParseObject-test.js
@@ -667,6 +667,14 @@ describe('ParseObject', () => {
       'objectField.number': 20,
       otherField: { hello: 'world' },
     });
+    expect(o.toJSON()).toEqual({
+      objectField: {
+        number: 20,
+        letter: 'a',
+      },
+      otherField: { hello: 'world' },
+      objectId: 'setNested',
+    });
   });
 
   it('can set multiple nested fields (regression test for #1450)', () => {