apollo-datasource-mongodb icon indicating copy to clipboard operation
apollo-datasource-mongodb copied to clipboard

Error: Converting circular structure to EJSON:

Open helipilot50 opened this issue 4 years ago • 9 comments

Hello,

I get the following error when I specify a TTL on findOneById, findByFields, etc

Error: Converting circular structure to EJSON:

I'm sure that it is caused by something weird in my Mongoose schema, Do you have ideas on how to debug the issue

Version: "apollo-datasource-mongodb": "^0.4.6",

helipilot50 avatar Aug 06 '21 14:08 helipilot50

same here

arielboitas avatar Sep 01 '21 23:09 arielboitas

I also have this issue, and I think it is caused by the way Mongoose models are represented in the memory. They always have circular structures. My solution for this is for now to just rely on lean Mongoose documents. They don't have any references to parents or something else it works again. In my usecase it is totally fine and also good for performance, but I'm not sure if there is something that speaks against this approach in general. @lorensr What do you think about using lean documents by default? If we can decide on a solution for this problem I will create a PR for this.

Or maybe add a flag to enable lean documents and then state in the documentation that the TTL option will only work in combination with lean documents when using Mongoose models.

jonasmeier1212 avatar Sep 02 '21 07:09 jonasmeier1212

I'm sure that it is caused by something weird in my Mongoose schema, Do you have ideas on how to debug the issue

There are a number of places in the code where EJSON.stringify is used. I recommend adding a test case to https://github.com/GraphQLGuide/apollo-datasource-mongodb/blob/master/src/tests/cache.test.js that reproduces the error, and then see which line the error is coming from, and we can think about how it can be modified.

@lorensr What do you think about using lean documents by default?

I'm not familiar with them, but I'm glad we at least have a workaround.

lorensr avatar Sep 04 '21 00:09 lorensr

So, the problem happens using Mongoose because this library tries to serialize a Mongoose “Document” instance, which contains a bunch of methods such as getters/setters, validation, virtuals, etc. Depending on how complex/nested the mongoose model is, extra references(inner Mongoose stuff) should exist, and the serialization through bson.EJSON.stringfy() seems to get a bit confused traversing it and causes that error.

There are a few approaches I’ve tested that solve the problem:

1 – Fetch all mongoose models using .lean() to avoid Mongoose hydration. That substantially reduces the object’s size and complexity as well as speed-up the queries since it returns a plain JS object. Thus, simple to be serialized/deserialized without any problems. Here is a comprehensive explanation from Mongoose about it. It seems to be the best choice, at least for most of the use cases where a mongoose document instance is not necessary for further operations like save, update, delete;

2 – Change the serialization process. It is unclear why bson.EJSON.stringify is in place for that once Mongoose/Mongo Nodejs driver does not return BSON document, but JS Objects instead. On my tests, the infamous JSON.stringify() seems to offer better serialization performance than bson.EJSON(.stringify()/.parse()) and bson(.serialize(), deserialize()). Not to say that it also can serialize those hydrated mongoose documents without errors. There are also plenty of other options like avro-js and protobuf-js for faster serialization, but they should require additional tests.

@lorensr, we can discuss a pull request for that if you want/need.

leonardootoni avatar Aug 10 '22 22:08 leonardootoni

It is unclear why bson.EJSON.stringify is in place

Might the JS objects have things like int32s that don't survive JSON.parse(JSON.stringify(o))?

https://github.com/mongodb/js-bson#ejsonstringifyvalue-replacer-space-options

lorensr avatar Aug 11 '22 01:08 lorensr

AFAIK, the Nodejs Mongo driver is the responsible layer for parsing/translating BSON to native JS objects and prop values during CRUD operations through it.

leonardootoni avatar Aug 11 '22 03:08 leonardootoni

Yeah, they're no longer binary BSON, but I think the object can have types that aren't supported by JSON (hence EJSON).

Would be happy to review a PR for approach 1.

lorensr avatar Aug 11 '22 03:08 lorensr

We at B42 have done approach 1 on our fork: https://github.com/B42-Training/apollo-datasource-mongodb I will create a PR out of it, but it has been a time since we have done it, so maybe it needs a bit of cleaning up. Currently, I don't have the time for doing this, maybe I can do it in two weeks.

jonasmeier1212 avatar Aug 11 '22 09:08 jonasmeier1212

It's done.✌

On Wed, Aug 10, 2022 at 11:23 PM Loren ☺️ @.***> wrote:

Yeah, they're no longer binary BSON, but I think the object can have types that aren't supported by JSON (hence EJSON).

Would be happy to review a PR for approach 1.

— Reply to this email directly, view it on GitHub https://github.com/GraphQLGuide/apollo-datasource-mongodb/issues/74#issuecomment-1211514459, or unsubscribe https://github.com/notifications/unsubscribe-auth/AIQZSETPXVVDHUUV7DPVZSTVYRW4NANCNFSM5BWAJTKQ . You are receiving this because you commented.Message ID: @.***>

--

Best regards,

Leonardo Otoni de Assis

leonardootoni avatar Aug 11 '22 13:08 leonardootoni