Dql mutation add duplicate records - dgraph

What I want to do
Prevent the dql mutation to add duplicates records
What I did
I add a graphql schema:
type Product {
id: ID!
name: String! #id #dgraph(pred: "Product.name")
slug: String! #id #dgraph(pred: "Product.slug")
image: String #dgraph(pred: "Product.image")
created_at: DateTime! #dgraph(pred: "Product.created_at")
updated_at: DateTime! #dgraph(pred: "Product.updated_at")
}
the above graphql schema has generated the bellow DQL schema:
<Product.created_at>: datetime .
<Product.image>: string .
<Product.name>: string #index(hash) #upsert .
<Product.slug>: string #index(hash) #upsert .
<Product.updated_at>: datetime .
<dgraph.drop.op>: string .
<dgraph.graphql.p_query>: string #index(sha256) .
<dgraph.graphql.schema>: string .
<dgraph.graphql.xid>: string #index(exact) #upsert .
type <Product> {
Product.name
Product.slug
Product.image
Product.created_at
Product.updated_at
}
type <dgraph.graphql> {
dgraph.graphql.schema
dgraph.graphql.xid
}
type <dgraph.graphql.persisted_query> {
dgraph.graphql.p_query
}
I run a mutation to add some data using: https://github.com/dgraph-io/dgo#running-a-mutation.
But it does not respect the #id added to the schema to some fields like "slug" and "name".
Using the graphql mutation this is working and respect the uniqueness by returning an error:"message": "couldn't rewrite mutation addProduct because failed to rewrite mutation payload because id aaaa already exists for field name inside type Product"
dgraph version v21.03.2

In Dql you have to handle this by your own using Upsert Block.
Or if you don't want the power of dql you can use the graphql which handle this stuff automatically.

Related

panic: reflect: call of reflect.Value.Interface on zero Value on GORM .Create()

I'm new to go and Backend and I'm Trying to make many-to-many relation between tables. I used this repo to make model:https://github.com/harranali/gorm-relationships-examples/tree/main/many-to-many
I Used GORM with postgresql.
My model:
type Book struct {
gorm.Model
Title string `json:"title"`
Author string `json:"author"`
Description string `json:"description"`
Category string `json:"Category"`
Publisher string `json:"publisher"`
AuthorsCard []*AuthorsCard `gorm:"many-to-many:book_authorscard;" json:"authorscard"`
}
type AuthorsCard struct {
gorm.Model
Name string `json:"name"`
Age int `json:"age"`
YearOfBirth int `json:"year"`
Biography string `json:"biography"`
}
After connecting to database and AutoMigrating:
func init() {
config.Connect()
db = config.GetDB()
db.AutoMigrate(&models.Book{}, &models.AuthorsCard{})
}
I've created Function to see how that relation works:
func TestCreate() {
var AuthorsCard = []models.AuthorsCard{
{
Age: 23,
Name: "test",
YearOfBirth: 1999,
Biography: "23fdgsdddTEST",
},
}
db.Create(&AuthorsCard)
var testbook = models.Book{
Title: "Test",
Author: "tst",
Description: "something",
}
db.Create(&testbook)
db.Model(&testbook).Association("AuthorsCard").Append(&AuthorsCard)
}
But got This Error:
panic: reflect: call of reflect.Value.Interface on zero Value [recovered]
panic: reflect: call of reflect.Value.Interface on zero Value
How can I deal with this "Null" problem and make proper relation?
UPD: The First part of a problem was connected to a version of GORM, After I changed old version(github.com/jinzhu/gorm v1.9.16) to new version (gorm.io/gorm v1.23.6) the problem with reflect Error gone.
but now, when I want to create new book, I get this Error:
/go/pkg/mod/gorm.io/driver/postgres#v1.3.7/migrator.go:119 ERROR: there is no unique constraint matching given keys for referenced table "authors_cards" (SQLSTATE 42830)
[28.440ms] [rows:0] CREATE TABLE "book_authorscard" ("book_id" bigint,"authors_card_id" bigint,PRIMARY KEY ("book_id","authors_card_id"),CONSTRAINT "fk_book_authorscard_authors_card" FOREIGN KEY ("authors_card_id") REFERENCES "authors_cards"("id"),CONSTRAINT "fk_book_authorscard_book" FOREIGN KEY ("book_id") REFERENCES "books"("id"))
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
UPD 2:
I decided to make a Migrator().DropTable(). That's kinda worked, and all Errors have gone. But still I get "authorscard": null as a response.
By reading the release note of Gorm v2 (https://gorm.io/docs/v2_release_note.html), I think that you are trying to use v2 feature with an old version (<v2). Try to use Gorm latest version.

AWS Amplify and GraphQL Interfaces

How would you deal with interfaces and using them for connections in a data model using the AWS Amplify Model Transforms?
interface User #model {
id: ID
email: String
created: AWSTimestamp
}
type ActiveUser implements User {
id: ID
first: String
last: String
email: String
created: AWSTimestamp
}
type InvitedUser implements User {
id: ID
email: String
created: AWSTimestamp
invitedBy: String
}
type Team #model {
users: [User] #connection
}
It seems like my choices are to put #model on the types but then I get separate Dynamo tables and queries on the Query once amplify update api is run.
Can the transformer support interfaces as documented here: https://docs.aws.amazon.com/appsync/latest/devguide/interfaces-and-unions.html
I also found some support tickets, but was wondering if there was anything out there that enabled this feature. Here are the support tickets I found:
https://github.com/aws-amplify/amplify-cli/issues/1037
https://github.com/aws-amplify/amplify-cli/issues/202
You only use #connection to link two databases together (which must be made from type and not interface), so if you don't want to do that then just get rid of the #connection and the Team database will simply have users be of type [User]. I am not entirely what you want to do but I would do something like:
type User #model {
id: ID
first: String!
last: String!
email: String!
created: AWSTimestamp
isActive: boolean
invitedBy: String
team: Team #connection(name: "UserTeamLink")
}
type Team #model {
users: [User!] #connection(name: "UserTeamLink")
}
Where the fields first, last, and email are required when creating a new user, and you can distinguish between an active user with a boolean, and when you query the User database it returns the Team item from the Team database as well (I am guessing you want other fields like team name, etc.?), so when you create a Team object you pass in the teamUserId (not shown below but created when using amplify) that will allow you to attach a newly created Team to an existing user or group of users.
I think you could keep the common fields in User, and extra info in separate type. Not sure if this is the best practice, but it should work for this scenario
enum UserType {
ACTIVE
INVITED
}
type User #model #key(name:"byTeam", fields:["teamID"]){
id: ID!
teamID: ID!
email: String
created: AWSTimestamp
type: UserType
activeUserInfo: ActiveUserInfo #connection(fields:["id"])
invitedUserInfo: InvitedUserInfo #connection(fields:["id"])
}
type ActiveUserInfo #key(fields:["userID"]){
userID: ID!
first: String
last: String
}
type InvitedUserInfo #key(fields:["userID"]){
userID: ID!
invitedBy: String
}
type Team #model {
id:ID!
users: [User!] #connection(keyName:"byTeam", fields:["id"])
}

replace ObjectId field with custom string for ObjectIdColumn in TypeORM/MongoDB

I have a NestJs REST API and use TypeORM with MongoDB. I want to create a entity called project. I started with a basic entity and I just read that I should use ObjectIdColumn instead of PrimaryColumn for MongoDB.
#Entity()
export class Project extends BaseEntity {
// The technical project name
#ObjectIdColumn({ generated: false })
public id: ObjectID;
// The display name
#Column({ unique: true })
public name: string;
// The project successor
#Column({ nullable: true })
public successorId: ObjectID;
// Configuration stuff for that project
#Column()
public configuration: object;
}
I would like to know if it's possible to replace that object id column with a primary column of type string. The id field is based on a special pattern, e.g. the name field
my awesome project
would result into
my-awesome-project
for the id field. Sure I made use of generated: false but I have to pass in a custom string instead of an ObjectID. Currently this is not possible because the docs say the ObjectID
Can be a 24 byte hex string, 12 byte binary string or a Number. http://mongodb.github.io/node-mongodb-native/2.1/api/ObjectID.html
So what needs to get done to use a custom string as an ID field? The only thing I can think of is creating a second field e.g. theRealId and treat it like the ID field and ignore the autogenerated ObjectId...
From what I've learnt, here is what you can do
#Entity()
export class UserEntity
{
#ObjectIdColumn()
_id: string;
#PrimaryColumn()
id: string;
// The display name
#Column({ unique: true })
public name: string;
#Column({ nullable: true })
public successorId: ObjectID;
#Column()
public configuration: object;
}
MongoDB will use _id as an internal id, that you do not expose through your program (and api, then)
You will work with the id, "normally', and it will be your primary key, generating automatically and so on
Source : personal learning, and Udemy course : NestJS Zero to Hero - Modern TypeScript Back-end Development

Golang official MongoDB driver ObjectID weird behavior

I am trying to use the official mongodb driver in golang and am seeing something unexpected.
If I have a struct like
type User struct {
ID primitive.ObjectID `json:"id" bson:"_id"`
Name string `json:"name" bson:"name"`
Email string `json:"email" bson:"email"`
}
I create a new instance of this with Name and Email but omit ID expecting that the DB will fill this with its value. Instead it uses all zeroes and so the second and so on inserts fail with
multiple write errors: [{write errors: [{E11000 duplicate key error collection: collection.name index: _id_ dup key: { : ObjectId('000000000000000000000000') }}]}, {<nil>}]
If I use a *primitive.ObjectID I get the same class of error only on null instead of zeroes
multiple write errors: [{write errors: [{E11000 duplicate key error collection: collection.name index: _id_ dup key: { : null }}]}, {<nil>}]
It doesn't matter if I use the omitempty directive or not, same result.
If I omit the ID field entirely, it works, but then my struct doesn't have that data on it.
Is there a way to have the DB handle the ID? Or MUST I explicitly call the NewObjectID() function on the struct?
It doesn't matter if I use the omitempty directive or not, same result.
omitempty tag on ID should work. For example:
type User struct {
ID primitive.ObjectID `json:"id" bson:"_id,omitempty"`
Name string `json:"name" bson:"name"`
Email string `json:"email" bson:"email"`
}
collection.InsertOne(context.Background(), User{Name:"Foo", Email:"Baz"})
If you don't specify the omitepmty tag, then the behaviour that you observed is just Go structs behaviour; whereby if any of struct fields are omitted it will be zero-valued. In this case because you have specified the field type to be primitive.ObjectID, ObjectId('000000000000000000000000') is the zero value.
This is the reason why you need to generate a value first before inserting, i.e.:
collection.InsertOne(context.Background(),
User{ ID: primitive.NewObjectID(),
Name: "Foo",
Email: "Bar"})
Is there a way to have the DB handle the ID?
Technically, it's the MongoDB driver that automatically generates the ObjectId if it's not supplied before sending to server.
You can try to use bson.M instead of a struct when inserting to leave out the _id field, i.e.
collection.InsertOne(context.Background(),
bson.M{"name":"Foo", "email":"Bar"})
Code snippet above is written using mongo-go-driver v1.3.x
The omitempty struct tag should work:
type User struct {
ID primitive.ObjectID `json:"id" bson:"_id,omitempty"`
Name string `json:"name" bson:"name"`
Email string `json:"email" bson:"email"`
}
The primitive.ObjectID type implements the bsoncodec.Zeroer interface, so it should be omitted from the document if it's the empty object ID (all 0's) and the driver will generate a new one for you. Can you try this and post the output?

S3Object GraphQL type in AppSync with Lambda datasource?

Is the S3Object GraphQL type that is available in AppSync (see Complex objects section in https://docs.aws.amazon.com/appsync/latest/devguide/building-a-client-app-ios.html) tied to dynamoDB, or could it be used with a Lambda datasource (say one connecting to a mongoDB)?
From the AWS docs linked above...
type Post {
id: ID!
author: String!
title: String
content: String
url: String
ups: Int
downs: Int
file: S3Object
version: Int!
}
type S3Object {
bucket: String!
key: String!
region: String!
}
input S3ObjectInput {
bucket: String!
key: String!
region: String!
localUri: String
mimeType: String
}
I haven't tried this, but you should be able to do what you're looking to accomplish and use a Lambda data source that reads/writes to something else like Mongo or even RDS. AppSync needs the GraphQL types of S3Object and S3ObjectInput along with the fields like bucket and so forth listed above for the client SDKs and codegen to properly build out objects, however the S3Link functionality is done in the resolver itself both for reading and writing. You could move this to your logic layer in a Lambda.
If you look at https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html#dynamodb-helpers-in-util-dynamodb you will see the mapping function signatures and output:
$util.dynamodb.toS3Object(String key, String bucket, String region) : Map
$util.dynamodb.toS3ObjectJson(String key, String bucket, String region) : String
$util.dynamodb.toS3Object(String key, String bucket, String region, String version) : Map
$util.dynamodb.toS3ObjectJson(String key, String bucket, String region, String version) : String
$util.dynamodb.fromS3ObjectJson(String) : Map
So if you want to move this logic to write/read into a Lambda that's completely possible. If you standup this sample you'll be able to reverse engineer it: https://github.com/aws-samples/aws-amplify-graphql