Hey Guys,
I have a problem with date and _id format for embedded document which has a array of object collection structure.
So for example, I have Client Model which has a embedMany relation to an embedded document called employee. So employee is an array of objects embedded to a client collection. See the example data below. I can override this method and do the filter but I'm wondering if this is something that can be implemented on the package?
{
"_id": "5a7a624bb9dfdc00a35c4669",
"name": "jo3qmldbuglcsmdgkcoc",
"label": "Beier Group",
"enabled": false,
"logo_image_id": "6d401890-a561-362a-b829-97cd3d20776e",
"created_at": "1987-07-28 19:33:55",
"updated_at": "2016-12-09 22:58:56",
"product_id": "5a7a624bb9dfdc00a35c4665",
"employees": [
{
"user_id": 931,
"name": "Gregory Stark",
"profile_image_id": "20c07f90-1846-329c-9544-30c45407b4ef",
"created_at": {
"$date": {
"$numberLong": "1490943600000"
}
},
"updated_at": {
"$date": {
"$numberLong": "1517969995000"
}
},
"_id": {
"$oid": "5a7a624bb9dfdc00a35c4673"
}
},
{
"user_id": 249,
"name": "Mrs. Rhoda Orn",
"profile_image_id": "b3e498de-ba91-325e-8e17-8258bdbb4362",
"created_at": {
"$date": {
"$numberLong": "1490943600000"
}
},
"updated_at": {
"$date": {
"$numberLong": "1517969995000"
}
},
"_id": {
"$oid": "5a7a624bb9dfdc00a35c4674"
}
}
]
}
Now the problem is, the _id and date of the embedded document (employee) when getting the client collection was formatted as MongoDB\BSON\ObjectId and object(MongoDB\BSON\UTCDateTime) respectively, instead of string. This is only happening for embedded document with array of objects format. I guess this is because the Jenssegers\Mongodb\Eloquent\Model.php only support first level of dot notation as you can see below.
public function attributesToArray()
{
$attributes = parent::attributesToArray();
// Because the original Eloquent never returns objects, we convert
// MongoDB related objects to a string representation. This kind
// of mimics the SQL behaviour so that dates are formatted
// nicely when your models are converted to JSON.
foreach ($attributes as $key => &$value) {
if ($value instanceof ObjectID) {
$value = (string) $value;
}
}
// Convert dot-notation dates.
foreach ($this->getDates() as $key) {
if (Str::contains($key, '.') && Arr::has($attributes, $key)) {
Arr::set($attributes, $key, (string) $this->asDateTime(Arr::get($attributes, $key)));
}
}
return $attributes;
}
i have the same problem.
Any updates on this? @jenssegers
When selecting as single doc, dates displays as a date
{
"_id": "5ca71ce0d542352064004034",
"title": "General review",
"status": "active",
"start_date": "2019-04-05 09:16:16.000000",
"end_date": "2038-01-19 03:14:07.000000",
"start_review_date": "2019-04-05 09:16:16.000000",
"submission_fee": 100,
"reward": 0,
"is_general_review_round": true,
"created_at": "2019-04-05 09:16:16.000000",
"updated_at": "2019-04-05 09:16:16.000000",
"proposals": [],
"demography": null
},
But on select as related object I have this date conversion issue...
{
"title": "Omnis perspiciatis aut voluptatem dolores vel repudiandae.",
"start_date": {
"$date": {
"$numberLong": "1554542206000"
}
},
"end_date": {
"$date": {
"$numberLong": "1556183806000"
}
},
"start_review_date": {
"$date": {
"$numberLong": "1555406206000"
}
},
"updated_at": {
"$date": {
"$numberLong": "1554455806312"
}
},
"created_at": {
"$date": {
"$numberLong": "1554455806312"
}
}
}
@janzell @SakyaVarro guys, have you found solution?
Any update on this issue?
Any update on this?
same here issue return json data format issue
[
{
"_id": "5e0aecc7439f1e1b8cf1b432",
"members": [
1,
3
],
"messages": [
{
"_id": {
"$oid": "5e0aece4439f1e1b8cf1b433"
},
"user_id": 3,
"text": "123",
"created_at": {
"$date": {
"$numberLong": "1577774308193"
}
},
"updated_at": {
"$date": {
"$numberLong": "1577774308193"
}
}
}
],
"created_at": "2019-12-31 14:37:59",
"updated_at": "2019-12-31 14:38:28",
"__v": 1
}
]
any suggestion return format _id to string, and date format to string. thanks
I've got the same issue. It seems that embedded Relationships are not getting serialized when calling the toArray() method on the parent model (which is called automatically by Laravel to prepare the data for the response).
Therefore no mutations specified in the model class (e.g. $dates, $casts etc.) being executed and the _id value remains an instance of the MongoDB\BSON\ObjectId.
To solve the problem i've extended the Jenssegers\Mongodb\Eloquent\Model class to be able to override the attributesToArray method:
class MyModel extends Jenssegers\Mongodb\Eloquent\Model
{
/**
* Added serialization for embedded documents.
*
* @inheritDoc
*/
public function attributesToArray()
{
$attributes = parent::attributesToArray();
foreach($attributes as $key => $value) {
if($this->isEmbedsRelationship($key)) {
$attributes[$key] = $this->serializeEmbedded($key);
}
}
return $attributes;
}
/**
* Determine if the given key belongs to an embeds one or an embeds many relationship.
*
* @param string $key
*
* @return bool
*/
public function isEmbedsRelationship(string $key): bool
{
return method_exists($this, $key) && $this->getAttribute($key) instanceof EmbedsOneOrMany;
}
/**
* Serialize all embedded models to apply all mutations defined in the model class and
* to serialize the MongoId to string.
*
* @param string $key
*
* @return mixed
*/
protected function serializeEmbedded(string $key)
{
$data = $this->getAttribute($key);
$model = $this->$key()->getRelated();
if($data instanceof EmbedsMany) {
return $model::hydrate($data->toArray());
}
$attribute = $this->getAttribute($key);
return ((new $model)->newInstance($attribute, true))->toArray();
}
}
To make this work you have to create a model class for each embedded document!
class User extends MyModel
{
public function address()
{
return $this->embedsOne(Address::class);
}
public function addresses()
{
return $this->embedsMany(Address::class);
}
}
class Address extends MyModel
{
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = ['created_at'];
/**
* The attributes that should be casted to native types.
*
* @var array
*/
protected $casts = ['created_at' => 'datetime:d.m.Y'];
}
When requesting a user all addresses are now serialized as expected.
Hi guys,
PRs are welcome, however keep in mind that support for embeds relationship will be dropped in the next version 4 release. The reason is simple, it doesn't work as people expect and has bugs which is nobody fixes.
Version 3.6 will continue to receive fixes only.
Thanks.
Any updates on when we can expect version 4? Wondering whether to use embedded documents or not on a new project now.
Any updates on when we can expect version 4? Wondering whether to use embedded documents or not on a new project now.
Hello @mattg66,
You can use embedded documents without the "eloquent" magic that this library provides. Embedded documents are fine, however, the "magic" is what is causing issues.
Regarding the new version don't expect it soon. Nobody likes breaking changes and it has been explained https://github.com/jenssegers/laravel-mongodb/issues/1974 that there things that need to fixed upstream which is never going to happen - you might know the reason already.
Thanks!