New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Wrong mapping of $id field. #1674
Comments
If I get the problem correctly, it stems from both embedded and parent document having |
@malarzm I'm not sure that's the issue. The query builder will look for mapping information in the metadata class for @iskyd Assuming you have a document manager along your query builder, could you try this?
|
@alcaeus that give me the right mongo query. |
Yeah, I expected it would. I’ll flag it as a bug and see if I can come up with something. |
This is also true for non-embedded documents. Consider the following (bad) example:
Despite the bad naming (_id vs id), this is a valid Mongo document (resulting from a direct import from a different data source). A direct query on the collection will work as expected but this can't be mapped using the following:
So that means we can't do:
But this works: |
I can confirm this behaviour described by @KarunaGovind! I use XML mapping and have two fields "_id" (the MongoId Object") and an extra ID "id". <field fieldName="id" name="_id" id="true" type="string" />
<field fieldName="employeeId" name="id" id="true" type="string" /> I explicitely set the names to "_id" and "id" but I always get the value of "_id". Maybe the I think I once got a warning that "id" was marked as identifier and this should not be changed. Would be great to have this fixed in the current version too. |
In ODM, both field name and name (aka database name) are immediately reserved and required to be unique. There may not be a field with a name equal to another fields $builder->field('someReference')->references($someObject); In this case, we wouldn't want you to have to know how exactly
This replicates behaviour from ORM, which is why it was built this way. Unfortunately, in your case this means that you'll have to find a different In the original example, this is a bit different: the query expression contains metadata for the original it was built for, which is why the |
TL;DR: no way for 1.x, no for 2.0. The version in the roadmap is still up-to-date. My initial idea was to update the While I understand that it is only a workaround, I would still recommend to manually inject a separate |
We currently switch to 2.0. If I see this correctly than it is still no possible to map the Mongo internal ObjectId Field "_id" to a different property on our model than |
I will have to correct myself on the last comment. Indeed our solution on order to keep the domain model clean and stay with our internal "$id" property we can do this: <id field-name="surrogateId" />
<field field-name="id" type="string" /> |
Just stumbled upon this issue again. Any updates? Refs: #1987 |
The code mentioned by @iskyd can be found in if (isset($mapping['id']) && $mapping['id'] === true) {
$mapping['name'] = '_id';
$this->identifier = $mapping['fieldName'];
if (isset($mapping['strategy'])) {
$this->generatorType = constant(self::class . '::GENERATOR_TYPE_' . strtoupper($mapping['strategy']));
} |
No updates to the issue. Having two fields share a name, even when one is the database name and the other is the property name in your domain model is not supported. The following mapping for example is invalid: <id field-name="id" />
<field name="id" field-name="applicationId" type="string" /> Written as annotations, this would correspond to this: /** @Id */
private $id;
/** @Field(name="id") */
private $applicationId; The reason this conflicts is that the query builder no longer knows what to do with this builder expression: $builder->field('id')->equals('value'); If the builder look at field names (meaning property names in your domain model), the resulting query would be:
However, the builder also supports passing database names, in which case the generated query would look like this:
Since the query builder doesn't know what to do here, this kind of mapping should be avoided at all costs. I'll note that the original issue wasn't about this, but rather that the query builder doesn't take field metadata into account when building expressions. In the original example, the $elemMatchExpr = $qb->expr();
$elemMatchExpr->setClassMetadata($dm->getClassMetadata(Embedded::class); // Makes sure correct translation rules are used
$qb
->field('embedded')
->elemMatch(
$elemMatchExpr
->field('id')
->equals(1)
)
; Not sure why I didn't think of this before, but that may solve the original problem @iskyd was reporting. @webdevilopers if there is a different issue you're referring to, please create a new issue and I'll investigate it. Thanks! |
Thanks for the instant feedback @alcaeus ! I get your point. Our use case is the following: We design persistence-ignorant Domain Models. We add our own IDs as value objects. The MongoDB required For instance: /**
* @MongoDB\Document(collection="account_details", readOnly=true)
*/
class Account
{
/**
* @MongoDB\Id()
* @internal
*/
protected $id;
/**
* @MongoDB\Field(type="string")
*/
protected $accountId;
} /**
* @MongoDB\Document(collection="business_profile_details", readOnly=true)
*/
class BusinessProfile
{
/**
* @MongoDB\Id()
* @internal
*/
protected $id;
/**
* @MongoDB\Field(type="string")
*/
protected $businessProfileId;
/**
* MongoDB\ReferenceOne(targetDocument=Account::class, storeAs="id", name="accountId")
*/
protected $account; The issue is that we cannot link these to documents via |
I understand, but not entirely. Here's what I'd do: /**
* @MongoDB\Document(collection="account_details", readOnly=true)
*/
class Account
{
/**
* @MongoDB\Id(type="string", strategy="none")
*/
protected $accountId;
} /**
* @MongoDB\Document(collection="business_profile_details", readOnly=true)
*/
class BusinessProfile
{
/**
* @MongoDB\Id(type="string", strategy="none")
*/
protected $businessProfileId;
/**
* MongoDB\ReferenceOne(targetDocument=Account::class, storeAs="id", name="accountId")
*/
protected $account;
} This will lead to these documents:
I'm not sure I understand what switching databases has to do with this. Here's the same document that doubles as an ORM entity for any SQL-based database: /**
* @MongoDB\Document(collection="account_details", readOnly=true)
* @ORM\Entity(readOnly=true)
* @ORM\Table(name="account_details")
*/
class Account
{
/**
* @MongoDB\Id(type="string", strategy="none")
* @ORM\Id
* @ORM\Column(type="string")
*/
protected $accountId;
/**
* @MongoDB\ReferenceMany(targetDocument=BusinessProfile::class, mappedBy="account")
* @MongoDB\ManyToOne(targetDocument=BusinessProfile::class, mappedBy="account")
*/
protected $businessProfiles;
} /**
* @MongoDB\Document(collection="business_profile_details", readOnly=true)
* @ORM\Entity(readOnly=true)
* @ORM\Table(name="business_profile_details")
*/
class BusinessProfile
{
/**
* @MongoDB\Id(type="string", strategy="none")
* @ORM\Id
* @ORM\Column(type="string")
*/
protected $businessProfileId;
/**
* @MongoDB\ReferenceOne(targetDocument=Account::class, storeAs="id", name="accountId")
* @MongoDB\ManyToOne(targetDocument=Account::class, inversedBy="businessProfiles")
*/
protected $account;
} But what about queries? One identifier is called $managerRegistry
->getManagerForClass(Account::class)
->createQueryBuilder(Account::class)
->field('accountId')
->equals('abc')
; I'm curious which part of your use-case I missed, because I've seen this work for projects. Maybe its due to SonataAdminBundle making false assumptions, in which case I'd happily help fixing this. |
@iskyd @webdevilopers #2299 fixes the original issue where the wrong |
I think this is a wrong behaviour about mapping field in an embedded document.
I'm using version: 3.1.0
This is my example:
Main document
Embedded document
In the embedded document there is a field called $id that is a string type, not @odm\Id.
The problem comes when i try to query that field.
This will result in this query:
"embedded":{"$elemMatch":{"_id":{"$id":"5a0d7aee26567e3c36166391"}}}
But i suppose to have:
"embedded":{"$elemMatch":{"id":1}}
So I investigate in the mapField function and i noticed that:
Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo line 1063: public function mapField(array $mapping)
The text was updated successfully, but these errors were encountered: