I’m using NextJS 15.0.0-rc.0, Mongoose 8.4.1, and React 19.0.0-rc-3563387fe3-20240621.
If you just attempt to send data from a server component to the client with even something simple like the below, you get this error: Only plain objects can be passed to Client Components from Server Components. Objects with toJSON methods are not supported. Convert it manually to a simple value
const ingredients = await IngredientModel.find().lean().exec();
So that’s easy enough to fix. Just run a map where you make _id a plain string or remove it from the object.
const transformedIngredients = ingredients.map(ing => {...ing, _id: ing._id.toString()})
And that works. But is it the best way? I’ve also seen that you can use virtuals to get a virtual id field where it’s already a string, but if you use those, you still have to remove _id via a mapping or other loop.
Some answers suggest using a global transform with toJSON
but this still requires mapping over each object and calling toJSON
.
mongoose.plugin((schema) => {
schema.options.toJSON = {
virtuals: true,
versionKey: false,
transform(doc, ret) {
ret.id = ret._id;
delete ret._id;
}
};
});
And then if you decide to add nested/sub documents, you’ll have to do any of the above steps for each of those.
So lean is meant for speed but still requires a transformation of some kind to send it to the client. toJSON
/toObject
aren’t fast but if you’re running a transform anyway, it seems like the better candidate. Plugins can help but they really only seem to make it so you don’t have to repeat code.
So all of this leads me to
- How should I be sending Mongo/Mongoose data to NextJS Client Components?
- Is there a way to use lean and have Mongoose convert the _id for me without needing a map?
- How should nested/sub documents be dealt with?
- Is mapping going to cause any slowdown problems, especially if there are a lot of fields with nested/sub documents?