Description
New Issue Checklist
- [X ] I am not disclosing a vulnerability.
- [X ] I am not just asking a question.
- [X ] I have searched through existing issues.
- [X ] I can reproduce the issue with the latest version of Parse Server.
Issue Description
Although not explicitly stated in the documentation, one is able to increment values in an embedded document. For example, with Metric
as our class with the following schema
{
topLevel: number,
stats: {
first: number,
second: number
}
}
One can call
metric.increment('stats.first')
This appropriately increments the value at Metric.stats.first
Where the bug shows up is when you save the metric
. The returned / updated value of metric
does NOT include the rest of the properties in the embedded document stats. Even if you had fetched the ENTIRE object prior to the increment command, the save will ONLY return the updated info of the embedded document property.
Steps to reproduce
- Fetch an object completely w/ all of its properties AND embedded object properties
- Increment an embedded document property
- Save the object
Actual Outcome
- Notice that ALL properties are present EXCEPT embedded document properties that were NOT incremented
Expected Outcome
- The entire object w/ all embedded document properties is returned
My guess is that inside the source code, we are not merging the updated value with a 'spread' version of the prior object properly. This despite having all of the values prior to the increment which is confirmed in the verbose log AND using VS Code to debug in real time.
Environment
Server
- Parse Server version: 4.2.0
- Operating system: Ubuntu & Mac OS 10.15
- Local or remote host (AWS, Azure, Google Cloud, Heroku, Digital Ocean, etc): Heroku & Local
Database
- System (MongoDB or Postgres): MongoDB
- Database version: 3.6.19 & 4.2.9
- Local or remote host (MongoDB Atlas, mLab, AWS, Azure, Google Cloud, etc): MongoDB Atlas
Client
- SDK (iOS, Android, JavaScript, PHP, Unity, etc): Javascript
- SDK version: n/a
Logs
verbose: REQUEST for [POST] /parse/batch: {
"requests": [
{
"method": "PUT",
"body": {
"answeredIncorrectlyCount": {
"__op": "Increment",
"amount": 1
},
"choiceStats.d2": {
"__op": "Increment",
"amount": 1
},
"ACL": {
"*": {
"read": true
}
}
},
"path": "/parse/classes/GlobalQuestionMetric/myGArd860W"
}
]
}
verbose: RESPONSE from [POST] /parse/batch: {
"response": [
{
"success": {
"answeredIncorrectlyCount": 6,
"choiceStats": {
"d2": 1
},
"updatedAt": "2020-09-09T17:18:59.695Z"
}
}
]
}
verbose: RESPONSE from [POST] /parse/functions/recordQuiz: {
"response": {
"result": {
"globalMetrics": [
{
"questionSerial": "12345",
"answeredCorrectlyCount": 14,
"createdAt": "2020-07-18T01:02:18.335Z",
"updatedAt": "2020-09-09T17:18:59.695Z",
"answeredIncorrectlyCount": 6,
"choiceStats": {
"d2": 1
},
"ACL": {
"*": {
"read": true
}
},
"objectId": "myGArd860W",
"__type": "Object",
"className": "GlobalQuestionMetric"
}
]
}
}
}
verbose: REQUEST for [GET] /parse/classes/GlobalQuestionMetric: {
"where": {
"objectId": {
"$in": [
"myGArd860W"
]
}
},
"limit": 1
}
verbose: RESPONSE from [GET] /parse/classes/GlobalQuestionMetric: {
"response": {
"results": [
{
"objectId": "myGArd860W",
"questionSerial": "12345",
"answeredCorrectlyCount": 14,
"createdAt": "2020-07-18T01:02:18.335Z",
"updatedAt": "2020-09-09T17:18:59.695Z",
"answeredIncorrectlyCount": 6,
"choiceStats": {
"a1": 2,
"a2": 2,
"d3": 2,
"d2": 1
},
"ACL": {
"*": {
"read": true
}
}
}
]
}
}