Skip to content
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

DataStore cannot find ID field of connected record #8285

Closed
3 tasks done
sacrampton opened this issue May 17, 2021 · 16 comments
Closed
3 tasks done

DataStore cannot find ID field of connected record #8285

sacrampton opened this issue May 17, 2021 · 16 comments
Assignees
Labels
DataStore Related to DataStore category

Comments

@sacrampton
Copy link

Before opening, please confirm:

JavaScript Framework

Not applicable

Amplify APIs

DataStore

Amplify Categories

api

Environment information

# Put output below this line
npx: installed 1 in 1.21s

  System:
    OS: Linux 4.14 Amazon Linux 2
    CPU: (2) x64 Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz
    Memory: 6.61 GB / 7.58 GB
    Container: Yes
    Shell: 4.2.46 - /bin/bash
  Binaries:
    Node: 10.23.1 - ~/.nvm/versions/node/v10.23.1/bin/node
    npm: 6.14.10 - ~/.nvm/versions/node/v10.23.1/bin/npm
  npmGlobalPackages:
    @aws-amplify/cli: 4.51.0
    cdk: 1.83.0
    coffeescript: 2.5.1
    esformatter: 0.11.3
    js-beautify: 1.13.2
    npm: 6.14.10
    prettier: 2.2.1
    typescript: 3.7.5

Describe the bug

See the code snippet below - but the id of the connected model is not available to query within DataStore.

In our GraphQL application, if I want to query for all assets in the same plant in GraphQL I would query for assetPlantId = the Plant ID I want and I can retrieve connected plant information.

However, in DataStore, whilst I can query for an asset and get related plant information when I query an asset, I can't query on the ID field (ie. assetPlantId) - it shows that it doesn't exist in the model even though it is in the GraphQL schema and I can query in GraphQL with it.

Expected behavior

That DataStore allows me to query the ID of the connected record

Reproduction steps

See code snippet below.

Code Snippet

// Put your code below this line.
type Asset @model{
  id: ID
  assetPlantId: ID
  plant: Plant @connection (field: "assetPlantId")
}

type Plant @model{
   id: ID
}

Log output

// Put your logs below this line


aws-exports.js

No response

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

No response

@chrisbonifacio chrisbonifacio added the DataStore Related to DataStore category label May 18, 2021
@sacrampton
Copy link
Author

It would appear that I have to manually add the following code to the schema.js file then it works fine. Problem is that I have 165 connections like this - that is 165 manual entries every time I change the model. Can amplify codegen models just include this field?

        "Asset": {
            "name": "Asset",
            "fields": {
                "assetPlantId": {
                    "name": "assetPlantId",
                    "isArray": false,
                    "type": "ID",
                    "isRequired": false,
                    "attributes": []
                }
             }

@sacrampton
Copy link
Author

Further discovery here. I have two connections like this in my schema.graphql

  plant: Plant @connection (fields: ["characteristicValuePlantId"])
  uom: Uom @connection (fields: ["characteristicValueUomId"])

In the schema.js that is generated by amplify codegen models it generates an association with connectionType as follows for the above two connections:
"connectionType": "BELONGS_TO"
"connectionType": "HAS_ONE"

If the connectionType is "BELONGS_TO" then "characteristicValuePlantId" field is not created. But if the connectionType is "HAS_ONE" then the "characteristicValueUomId" field is created.

I can't see why one would be created as BELONGS_TO versus HAS_ONE and why BELONGS_TO is not creating the id field like HAS_ONE is doing.

@iartemiev
Copy link
Member

Hey @sacrampton , in your issue description there seems to be a typo, so I just want to clarify.
You have plant: Plant @connection (field: "assetPlantId") with a field param, but it needs to be fields (plural) with an array as the value. When testing model generation with the schema in your example and the corrected syntax,

type Asset @model {
  id: ID
  assetPlantId: ID
  plant: Plant @connection(fields: ["assetPlantId"])
}

I get the following generated schema for the model (assetPlantId is included in the fields):

  "Asset":{
    "name":"Asset",
    "fields":{
      "id":{
        "name":"id",
        "isArray":false,
        "type":"ID",
        "isRequired":true,
        "attributes":[
          
        ]
      },
      "assetPlantId":{
        "name":"assetPlantId",
        "isArray":false,
        "type":"ID",
        "isRequired":false,
        "attributes":[
          
        ]
      },
      "plant":{
        "name":"plant",
        "isArray":false,
        "type":{
          "model":"Plant"
        },
        "isRequired":false,
        "attributes":[
          
        ],
        "association":{
          "connectionType":"HAS_ONE",
          "associatedWith":"id",
          "targetName":"assetPlantId"
        }
      }
    },
    "syncable":true,
    "pluralName":"Assets",
    "attributes":[
      {
        "type":"model",
        "properties":{
          
        }
      }
    ]
  }

@iartemiev
Copy link
Member

I'd also make sure that you're using a recent version of the Amplify CLI with this feature flag set to true, as this will enable a bug fix for deleting Has One relationships (related issue: #6560)

@sacrampton
Copy link
Author

Hi @iartemiev - thanks for your message. Firstly, yes that field/fields thing was a typo above. Secondly, the above is generating for you as "HAS_ONE", whereas most of mine are generating as "BELONGS_TO" (154 instances Vs 12 HAS_ONE instances).

A little more expansion on this - I think that if I have a 2 sided connection it is causing the BELONGS_TO rather than HAS_ONE to be created - and not creating the assetPlantId field on the Asset model.

type Asset
   @model
   @key(name: "byAssetPlantId", fields: ["assetPlantId"], queryField: "AssetPlant") 
 {
     id: ID
     assetPlantId: ID
     plant: Plant @connection(fields: ["assetPlantId"])
}

type Plant @model{
   id: ID
  asset: [Asset] @connection (keyName: "byAssetPlantId", fields: ["id"])
}

This is the cli.json that I am using.

{
  "features": {
    "graphqltransformer": {
      "addmissingownerfields": true,
      "validatetypenamereservedwords": true,
      "useexperimentalpipelinedtransformer": false,
      "enableiterativegsiupdates": true
    },
    "frontend-ios": {
      "enablexcodeintegration": true
    },
    "auth": {
      "enablecaseinsensitivity": true
    },
    "codegen": {
      "useappsyncmodelgenplugin": true
    }
  }
}

@sacrampton
Copy link
Author

sacrampton commented May 21, 2021

This is also causing us issues in DataStore Sync

DataStore.configure({
syncExpressions: [
syncExpression(Asset, () => {
return asset => asset.assetPlantId('eq', "0d6acebc-xxxx-4b0c-97e5-6b9e32f879a8");
}),
Error- Property 'assetPlantId' does not exist on type 'ModelPredicate<Asset>

@sacrampton
Copy link
Author

Hi @iartemiev - can you comment on this - when I do amplify codegen models and I have a "one sided connection" it generates a "HAS_ONE" connectionType - and importantly it includes the targetName as a field on the model.

                "uom": {
                    "name": "uom",
                    "isArray": false,
                    "type": {
                        "model": "Uom"
                    },
                    "isRequired": false,
                    "attributes": [],
                    "association": {
                        "connectionType": "HAS_ONE",
                        "associatedWith": "id",
                        "targetName": "assetVisitAttributeUomId"
                    }
                },
                "assetVisitAttributeUomId": {
                    "name": "assetVisitAttributeUomId",
                    "isArray": false,
                    "type": "ID",
                    "isRequired": false,
                    "attributes": []
                },

BUT, if the connection has 2 sides (ie. @key ) then it creates a BELONGS_TO connectionType. It does not include "associatedWith": "id" in the association and it does not include the targetName as a field that is then queryable.

                "brandSynonym": {
                    "name": "brandSynonym",
                    "isArray": false,
                    "type": {
                        "model": "BrandSynonym"
                    },
                    "isRequired": false,
                    "attributes": [],
                    "association": {
                        "connectionType": "BELONGS_TO",
                        "targetName": "assetVisitAttributeBrandSynonymId"
                    }
                },

At the moment I have to manually add the targetName field to the schema.js file for BELONGS_TO connections - and in the index.d.ts I need to add the same fields to "export declare class ".

Any thoughts/comments appreciated - am concerned about such significant edits I'm having to make to codegen models.

@iartemiev
Copy link
Member

@sacrampton that is currently the expected behavior for Has One vs. Belongs To, however, we're looking into including the connection field in the generated model, so that it can be queryable.

@sacrampton
Copy link
Author

@iartemiev - just want to confirm that by editing the schema.js to add the fields (had to make them optional even if they were mandatory) and the "export declare class " in the index.d.ts files that this gets DataStore working with those fields being queryable. Is a significant undertaking the first time - but after that you can use something like Visual Studio Code to manage changes between versions without having to redo everything.

@iartemiev
Copy link
Member

iartemiev commented May 24, 2021

Thank you, @sacrampton, I understand that that's the workaround you're using.

Before we (the Amplify team) make that change in the codegen library, we need to consider the ramifications of doing so and whether there are better alternatives for exposing those fields. I'll keep this issue updated as we make progress on this.

@stale
Copy link

stale bot commented Jun 26, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale
Copy link

stale bot commented Jul 21, 2021

This issue has been automatically closed because of inactivity. Please open a new issue if are still encountering problems.

@stale stale bot closed this as completed Jul 21, 2021
@chrisbonifacio chrisbonifacio self-assigned this Jul 22, 2021
@civicevolution
Copy link

Are there any work-arounds for this problem?

@justinjaeger
Copy link

justinjaeger commented Aug 23, 2022

This appears to still be an issue. I'd like to query by the "belongsTo" ID but cannot, even though as @sacrampton pointed out, if you manually add this field (relatedId) in schema.js, it works as expected. I'm not sure why this is something DataStore doesn't do automatically when creating your schema.

If I'm specifying a field of relatedId in my schema, I'd expect it to be queryable.

However, it does seem like there's a solution to this, even though I found it slightly unintuitive:
https://docs.amplify.aws/lib/datastore/relational/q/platform/js/#saving-relations

So I appreciate the documentation there.

@justinjaeger
Copy link

justinjaeger commented Aug 23, 2022

I also discovered that if you omit the "fields" argument in a connection, this will sometimes give you access to the relatedID field. It creates the field in the schema.js file, same as @sacrampton was doing manually. However, this doesn't seem to ALWAYS work, and I can't say why. But it may be worth a shot.

type Comment @model {
id: ID!
postID: ID! @Index(name: "byPost", sortKeyFields: ["content"])
post: Post! @belongsTo(fields: ["postID"]) => INSTEAD, DO THIS: @belongsTo
content: String!
}

@sacrampton
Copy link
Author

Hi @justinjaeger - just FYI, your example follows the V2 transformer syntax. If you have an existing production system of any size then you can't move from the V1 schema due to the failures around stack mapping (aws-amplify/amplify-category-api#32). Until we are able deal with these ongoing issues with the V2 transformer we are all stuck on V1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
DataStore Related to DataStore category
Projects
None yet
Development

No branches or pull requests

5 participants