parse-community / parse-server

Parse Server for Node.js / Express
https://parseplatform.org
Apache License 2.0
20.69k stars 4.76k forks source link

Custom objectId not working #9134

Closed badboy-tian closed 1 month ago

badboy-tian commented 1 month ago

New Issue Checklist

Issue Description

"Error: Object not found"

Steps to reproduce

allowCustomObjectId: true,
router.post("/", async (req, res) => {
    const body = req.body;
    logInfo(body)
    logInfo(JSON.stringify(body))

    const name = body.name;
    const data = JSON.parse(body.data);

    const testObject = new Parse.Object(name);
    testObject.id = data.objectId;

    const entries = Object.entries(data);
    const map = [];
    for (let i = 0; i < entries.length; i++) {
        map.push({
            key: entries[i][0],
            value: entries[i][1]
        })
    }

    for (let i = 0; i < map.length; i++) {
        const key = map[i].key;
        const value = map[i].value;
        if (key === "__after") {
            continue;
        }

        if (key === "createdAt" || key === "updatedAt") {
            testObject.set(key, moment(value).toDate());
            continue;
        }

        //处理Pointer
        if (typeof value === "object" && value.__type === "Pointer") {
            let className = value.className;
            if (className === "_File") {
                className = "AVFile";
            }
            const InnerObject = Parse.Object.extend(className);
            testObject.set(key, InnerObject.createWithoutData(value.objectId))
        } else {
            testObject.set(key, value);
        }
    }

    console.log(testObject.toJSON())
    await testObject.save(null, {useMasterKey: true});
    res.send("ok: " + testObject.id);
})

postman:

{"name":"SaveAudio","data":"{\"__after\":\"1716789397109,55162b88c4cb04b2c1fd05ef25090427203e6cb8\",\"isDeleted\":false,\"name\":\"ssssss\",\"duration\":4,\"url\":\"http://file2.xxx.com/pENLbCtZEPShbPofnH8mk2YS28cc6EO7KNCEX12d.mp3\",\"user\":{\"__type\":\"Pointer\",\"className\":\"_User\",\"objectId\":\"65486642151c6a7a80c2e7aa\"},\"pack\":{\"__type\":\"Pointer\",\"className\":\"SaveAudioPack\",\"objectId\":\"66542034bd8b97410c194605\"},\"objectId\":\"66542095ac7d473fc944bfb0\",\"createdAt\":\"2024-05-27T05:56:37.105Z\",\"updatedAt\":\"2024-05-27T05:56:37.105Z\"}"}

Actual Outcome

{"code":101,"stack":"Error: Object not found}

Expected Outcome

ok: objectId

Environment

Server

Database

Client

Logs

 verbose: REQUEST for [GET] /parse/classes/_JobSchedule: {
[TS]   "where": {}
[TS] } {"body":{"where":{}},"headers":{"accept":"*/*","connection":"close","content-length":"174","content-type":"text/plain","host":"localhost:1337","user-agent":"node-XMLHttpRequest, Parse/js5.0.0 (NodeJS 16.14.2)"},"method":"GET","url":"/parse/classes/_JobSchedule"}
[TS] verbose: RESPONSE from [GET] /parse/classes/_JobSchedule: {
[TS]   "response": {
[TS]     "results": []
[TS]   }
[TS] } {"result":{"response":{"results":[]}}}
[TS] info: 16:49:14 -> 0 job(s) scheduled.
[TS] info: 16:49:18 -> {"name":"SaveAudio","data":"{\"__after\":\"1716789397109,55162b88c4cb04b2c1fd05ef25090427203e6cb8\",\"isDeleted\":false,\"name\":\"就算是夏天,也要少喝冰的\",\"du
ration\":4,\"url\":\"http://file2.xxxx.com/pENLbCtZEPShbPofnH8mk2YS28cc6EO7KNCEX12d.mp3\",\"user\":{\"__type\":\"Pointer\",\"className\":\"_User\",\"objectId\":\"65486642151c6a7a80c2
e7aa\"},\"pack\":{\"__type\":\"Pointer\",\"className\":\"SaveAudioPack\",\"objectId\":\"66542034bd8b97410c194605\"},\"objectId\":\"66542095ac7d473fc944bfb0\",\"createdAt\":\"2024-05-27T05:56:37.105Z\",\"updatedAt\":\"2024-05-27T05:56:37.105Z\"}"}
[TS] info: 16:49:18 -> {"name":"SaveAudio","data":"{\"__after\":\"1716789397109,55162b88c4cb04b2c1fd05ef25090427203e6cb8\",\"isDeleted\":false,\"name\":\"就算是夏天,也要少喝冰的\",\"du
ration\":4,\"url\":\"http://file2.xxxxx.com/pENLbCtZEPShbPofnH8mk2YS28cc6EO7KNCEX12d.mp3\",\"user\":{\"__type\":\"Pointer\",\"className\":\"_User\",\"objectId\":\"65486642151c6a7a80c2
e7aa\"},\"pack\":{\"__type\":\"Pointer\",\"className\":\"SaveAudioPack\",\"objectId\":\"66542034bd8b97410c194605\"},\"objectId\":\"66542095ac7d473fc944bfb0\",\"createdAt\":\"2024-05-27T05:56:37.105Z\",\"updatedAt\":\"2024-05-27T05:56:37.105Z\"}"}
[TS] {
[TS]   isDeleted: false,
[TS]   name: '就算是夏天,也要少喝冰的',
[TS]   duration: 4,
[TS]   url: 'http://file2.xxxx.com/pENLbCtZEPShbPofnH8mk2YS28cc6EO7KNCEX12d.mp3',
[TS]   user: {
[TS]     __type: 'Pointer',
[TS]     className: '_User',
[TS]     objectId: '65486642151c6a7a80c2e7aa'
[TS]   },
[TS]   pack: {
[TS]     __type: 'Pointer',
[TS]     className: 'SaveAudioPack',
[TS]     objectId: '66542034bd8b97410c194605'
[TS]   },
[TS]   objectId: '66542095ac7d473fc944bfb0'
[TS] }
[TS] verbose: REQUEST for [PUT] /parse/classes/SaveAudio/66542095ac7d473fc944bfb0: {
[TS]   "isDeleted": false,
[TS]   "name": "就算是夏天,也要少喝冰的",
[TS]   "duration": 4,
[TS]   "url": "http://file2.xxxx.com/pENLbCtZEPShbPofnH8mk2YS28cc6EO7KNCEX12d.mp3",
[TS]   "user": {
[TS]     "__type": "Pointer",
[TS]     "className": "_User",
[TS]     "objectId": "65486642151c6a7a80c2e7aa"
[TS]   },
[TS]   "pack": {
[TS]     "__type": "Pointer",
[TS]     "className": "SaveAudioPack",
[TS]     "objectId": "66542034bd8b97410c194605"
[TS]   }
[TS] } {"body":{"duration":4,"isDeleted":false,"name":"就算是夏天,也要少喝冰的","pack":{"__type":"Pointer","className":"SaveAudioPack","objectId":"66542034bd8b97410c194605"},"url":"htt
p://file2.xxxx.com/pENLbCtZEPShbPofnH8mk2YS28cc6EO7KNCEX12d.mp3","user":{"__type":"Pointer","className":"_User","objectId":"65486642151c6a7a80c2e7aa"}},"headers":{"accept":"*/*","con
nection":"close","content-length":"495","content-type":"text/plain","host":"localhost:1337","user-agent":"node-XMLHttpRequest, Parse/js5.0.0 (NodeJS 16.14.2)"},"method":"PUT","url":"/parse/classes/SaveAudio/66542095ac7d473fc944bfb0"}
[TS] error: Object not found. {"code":101,"stack":"Error: Object not found.\n    at D:\\Test\\parse\\node_modules\\parse-server\\src\\Controllers\\DatabaseController.js:632:19\n    at processTicksAndRejections (node:internal/process/task_queues:96:5)"}
[TS] error: 16:49:18 -> Unhandled Rejection at: Promise
[TS] error: 16:49:18 -> {}
[TS] error: 16:49:18 ->  reason:
[TS] error: 16:49:18 -> Error: Object not found.
[TS]     at handleError (D:\Test\parse\node_modules\parse-server\node_modules\parse\lib\node\RESTController.js:298:17)
[TS]     at processTicksAndRejections (node:internal/process/task_queues:96:5)
parse-github-assistant[bot] commented 1 month ago

Thanks for opening this issue!

mtrezza commented 1 month ago

I believe there are already tests for custom obj ID, so why don't they fail? Could you please create a PR with a minimal test that demos how yours fails?

badboy-tian commented 1 month ago

@mtrezza i have search in issues page. but i can not custom objectId

 const testObject = new Parse.Object(name);
    testObject.id = data.objectId;

console.log(testObject.toJSON())
    await testObject.save(null, {useMasterKey: true});
 {
[TS]   isDeleted: false,
[TS]   name: '认错',
[TS]   duration: 40,
[TS]   url: 'http://file2.xxxxx.com/ehDBv1dKDhPznwQKdJrUcw830wpJDVv5h7JxvIwV.mp3',
[TS]   user: {
[TS]     __type: 'Pointer',
[TS]     className: '_User',
[TS]     objectId: '5e5fce3a5620714cccad88bc'
[TS]   },
[TS]   pack: {
[TS]     __type: 'Pointer',
[TS]     className: 'SaveAudioPack',
[TS]     objectId: '60ae2c9392183125ad69feb2'
[TS]   },
[TS]   objectId: '66548045b32fe80e3ffcec2c'
[TS] }

but

 Object not found. {"code":101,"stack":"Error: Object not found.\n    at /Users/tian/Documents/work/android/parse/node_modules/parse-server/src/Controllers/DatabaseController.js:632:19\n    at processTicksAndRejections (node:internal/process/task_queues:95:5)"}
mtrezza commented 1 month ago

Could you please open a PR with a failing test

badboy-tian commented 1 month ago

I do not know how to make pr. but i write a simple code.

https://gist.github.com/badboy-tian/3bb44139d2346f159fd4cd9e5cf5aecb

badboy-tian commented 1 month ago

@mtrezza

badboy-tian commented 1 month ago

I create TestCustomObjectId.spec.js

'use strict';
const Parse = require('parse/node');
const moment = require('moment');

describe('Test Custom ObjectId', () => {
  it('object not found ', async () => {
    Parse.initialize('debug_appid', 'debug_key', 'debug_masterKey');
    Parse.serverURL = 'http://localhost:1337/parse';

    const body = {
      name: 'SaveAudio',
      data: '{"__after":"1716788669509,2cf6e3698932972402fa3ca2405b437dc3ac727a","isDeleted":false,"name":"好的呢,宝宝","duration":2,"url":"http://file2.xxx.com/FdD9KwF4xNgBHTiGcJByMNs6P470XNFp/20240405195209.mp3","user":{"__type":"Pointer","className":"_User","objectId":"65de1d08caa7af401d105a56"},"pack":{"__type":"Pointer","className":"SaveAudioPack","objectId":"65e9fcec4567a26864d47d2b"},"objectId":"66541dbdffead844f1339e3c","createdAt":"2024-05-27T05:44:29.504Z","updatedAt":"2024-05-27T05:44:29.504Z"}',
    };
    const name = body.name;
    const data = JSON.parse(body.data);

    const testObject = new Parse.Object(name);
    testObject.id = data.objectId;

    const entries = Object.entries(data);
    const map = [];
    for (let i = 0; i < entries.length; i++) {
      map.push({
        key: entries[i][0],
        value: entries[i][1],
      });
    }

    for (let i = 0; i < map.length; i++) {
      const key = map[i].key;
      const value = map[i].value;
      if (key === '__after') {
        continue;
      }

      if (key === 'createdAt' || key === 'updatedAt') {
        testObject.set(key, moment(value).toDate());
        continue;
      }

      //处理Pointer
      if (typeof value === 'object' && value.__type === 'Pointer') {
        let className = value.className;
        if (className === '_File') {
          className = 'AVFile';
        }
        const InnerObject = Parse.Object.extend(className);
        testObject.set(key, InnerObject.createWithoutData(value.objectId));
      } else {
        testObject.set(key, value);
      }
    }

    console.log(testObject.toJSON());
    await testObject.save(null, { useMasterKey: true });
  });
});

and then

npm test .\spec\TestCustomObjectId.spec.js

error:

F
  Test Custom ObjectId
    × object not found
      - Error: Object not found.

Failures:
1) Test Custom ObjectId object not found
  Message:
    Error: Object not found.
  Stack:
    error properties: Object({ code: 101 })
    Error: Object not found.
        at handleError (D:\web\parse-server\node_modules\parse\lib\node\RESTController.js:298:17)
        at processTicksAndRejections (node:internal/process/task_queues:96:5)

1 spec, 1 failure
Finished in 0.108 seconds
Randomized with seed 96374 (jasmine --random=true --seed=96374)
**************************************************
*                    Failures                    *
**************************************************

1) Test Custom ObjectId object not found
  - Error: Object not found.

Executed 1 of 1 spec (1 FAILED) in 0.109 sec.
Randomized with seed 96374.
badboy-tian commented 1 month ago

@mtrezza please take a look

badboy-tian commented 1 month ago

@mtrezza I make a new PR, please take a look. can not custom objectId.

badboy-tian commented 1 month ago

My app has an old server, and I want to use parse-server to implement a new server while it is running. Since the old app cannot be updated, I want the user to synchronize a copy when updating classes on the old server. The data comes to the new server. After the new server receives the data, it creates new data and saves it. The passed data contains objectId, so I want to implement custom objectId.