Define Multiple-Columns as PK in YDN-DB - ydn-db

When define a schema with ydn-db I can define a single column as PK with this code:
var products = {
name: 'products',
keyPath: 'id_product',
autoIncrement: true,
indexes: [
{keyPath: 'id_product'},
{keyPath: 'id_supplier'}
]
};
var schema = {
stores: [products]
};
How I can define a Store (table) with one PK with two columns or more? Thanks

How I can define a Store (table) with one PK with two columns or more?
I am not sure answering your question. IndexedDB (ynd-db is very IDB centric) can have only one PK. But primary key can be compound key compose of multiple keyPath (column) using array keypath. It is define like this
var products = {
name: 'products',
keyPath: ['id_category', id_product']
};

Related

How to retrieve only the relation ID, not the whole entity in MikroORM?

I have the following basic test entities:
#Entity()
class Author {
#PrimaryKey()
public id!: number;
#Property()
public name!: string;
}
#Entity()
class Book {
#PrimaryKey()
public id!: number;
#Property()
public title!: string;
#ManyToOne({joinColumn: 'authorID'})
public author!: Author;
}
What i'm trying, is to select only a single Book record, with its 'author', but I care only about its ID, I don't want to actually load the entity.
If I simply call this, it won't work (no author data loaded at all):
em.getRepository(Book).findOne({id: 1}, {fields: ['id', 'title', 'author.id']});
'author.id' doesn't do the trick, the SQL doesn't even contain the 'authorID' field.
If I add 'author' to the fields list as well, it works, author is loaded (only with the ID), but as a separate entity, with a separate, additional SQL statement! That's what I'm trying to avoid.
em.getRepository(Book).findOne({id: 1}, {fields: ['id', 'title', 'author', 'author.id']})
#1. SQL
select `b0`.`id`, `b0`.`title`, `b0`.`authorID` from `book` as `b0` where `b0`.`id` = 1 limit 1
#2. SQL (this wouldn't be neccessary as I want only the ID)
select `a0`.`id` from `author` as `a0` where `a0`.`id` in (2)
--> Result:
Book: { id: 1, title: 'a book', author: { id: 2 } }
The only way I found is to add the specific 'authorID' field too to the Book entity:
#Property()
public authorID!: number;
But, I'd like to avoid introducing these foreign key columns, it would be better to handle through the already existing and used 'author' relation (only by the 'id' property).
Does any solution exists where I could retrieve a relation's ID without generating a 2nd SELECT statement (for the relation), and even avoid introducing the foreign key (next to the already existing relation property)? Would be great to receive through the relation without any extra sql statement.
Thanks in advance.
It is correct behaviour you see the second query, that is how population works, and the fact that you want just a single property from the entity does not change anything, you still populate the relation, and each relation will use its own query to load it. You can use LoadStrategy.JOINED if you want to use a single query. But that would still do a join for that relation, which is not needed for your use case.
Given you only want the FK to be present, you dont need to care about the target entity at all. This should do the trick too:
em.getRepository(Book).findOne(1, {
fields: ['id', 'title', 'author'],
populate: [],
});
This way you say you want those 3 properties to be part of what's selected from the Book entity. You already have the author property, which represents the FK. You will end up with what you want once you serialize such entity. During runtime, you will see entity reference there - an entity with just the PK. It is represented as Ref<Author> when you console.log such entity.
Note that you need that populate: [] there, as otherwise it would be inferred from your fields which contains author property, and that would trigger the full load of it.

How to order ngrx entity collection

I have a response from backend like this:
[{ id: 4, name: 'Andrew'},
{id: 3, name: 'Rebecca'},
{id: 2, name: 'Joseph'},
{id: 1, name: 'Kristin'}]
The order is by descending id. From the last one to first one.
I have an entityAdapter defined in this way:
export const folderAdapter: EntityAdapter<Person> = createEntityAdapter<Person>({
selectId: person => person.id,
sortComparer: false,
});
into the reducer I created this function:
on(PeopleActions.loadAllPeople, (state, action): PeopleState => {
return {
...state,
people: adapter.addMany(action.people, state),
};
}),
when I go to see my state I have this situation:
ids:[4,3,2,1],
entities: {1: {id: 1, name: 'Kristin'}, 2: {id: 2, name: 'Joseph'}, 3: {id: 3, name: 'Rebecca'}, 4: { id: 4, name: 'Andrew'}}
}
This also happen into the ngFor. I tried to set return value to zero in ngfor keyvalue but nothing change. How can I change the order in entities? is there a particular property?
The EntityAdapter has the parameter sortComparer for this exact purpose.
All you need it to instead of using
sortComparer: false
you give it the function you would like to have sorting your entity ids
sortComparer: (a ,b) => a.id - b.id
As per ngrx's docs:
If provided, the state.ids array will be kept in sorted order based on comparisons of the entity objects, so that mapping over the IDs array to retrieve entities by ID should result in a sorted array of entities.
If not provided, the state.ids array will not be sorted, and no guarantees are made about the ordering. In other words, state.ids can be expected to behave like a standard Javascript array.

Cloud Firestore : Query nested map of arrays

My firestore document structure looks like this
doc1
{
name: 'Test',
categories: [
{
allNames: ['name1', 'name2', 'name3],
id: 'abcd'
},
{
allNames: ['name4', 'name5'],
id: 'xyz'
},
]
doc2
{
name: 'Test2',
categories: [
{
allNames: ['name7'],
id: 'abcd3'
},
{
allNames: ['name4', 'name5'],
id: 'xyz'
},
]
I am using the JS SDK and wanted to query all document with a certain category(id or name). So if I query with categories.id equal to xyz or categories.allNames contains name1, both the above documents should be returned.
Are both these queries possible or do I need to remodel my data ?
Thank you !
You cannot query arrays that way. If you know the exact object then you could use array-contains as shown below:
firestore.collection('col').where('categories', 'array-contains', {id: 'abc', allNames: ['name1']})
One solution would be to store another array which contains category IDs only like this:
{
name: 'Test1',
categories: [...],
categoryIds: ['abcd', 'xyz']
}
Now you can use arrayContains even if you know the category ID only and not the whole object in categories array. The same method can be used for allNames.
Categories can also be made a sub-collection where each object in categories array would be a document. Then you can use Collection Group queries to find category documents with that ID or allNames and find parent document ID using the DocumentReference.

DynamoDB - UpdateItem where X <= Y

I have a DynamoDb table defined with a composite key of
$response = $this->dynamoDb->createTable([
...
'KeySchema' => [
[
'AttributeName' => 'product_code',
'KeyType' => 'HASH'
],
[
'AttributeName' => 'token',
'KeyType' => 'RANGE'
]
]
...
]);
I want to be able to update all records where "product_code" = "X" and "created_at" <= "Y". I assume it must be possible but I am a bit stumped. The updateItem method requires the full key but I want a conditional update without specifying a key. My latest stub reads as
$response = $this->dynamoDb->updateItem([
'TableName' => 'products',
'ExpressionAttributeValues' => [
':val1' => ['N' => (string)$this->input['product_code']]
':val2' => ['N' => (string)$this->product['created_at']['N']],
':val3' => ['N' => (string)strtotime("now")],
],
'ConditionExpression' => 'product_code = :val1 AND processed_at <= :val2',
'UpdateExpression' => 'set processed_at = :val3'
]);
But the generated error message reads as follows:
[Key] is missing and is a required parameter
Which command should I be using? Any help building my query is greatly appreciated.
The following is taken from AWS DynamoDB API reference for UpdateItem:
For the primary key, you must provide all of the attributes. For example, with a simple primary key, you only need to provide a value for the partition key. For a composite primary key, you must provide values for both the partition key and the sort key.
In your code (the update item part) you provide only hash key (product_code). You have to provide the range key (token) as well in your ConditionExpression property, because you defined a composite key.
EDIT:
(regarding the comment)
The following describes the parameters for UpdateItem:
Request Parameters
...
Key
The primary key of the item to be updated. Each element consists of an
attribute name and a value for that attribute.
For the primary key, you must provide all of the attributes. For
example, with a simple primary key, you only need to provide a value
for the partition key. For a composite primary key, you must provide
values for both the partition key and the sort key.
Type: String to AttributeValue object map
Required: Yes
...
As you can see, the primary key is required for an UpdateItem operation.
So you cannot use a secondary index to point UpdateItem to a collection of items to update.
However, you can query the table by a secondary index, and collect the primary keys of the resulted items, say in an array keysToUpdate.
Then you can update the desired items, whose keys are in keyToUpdate.

Update an Entity with Unique Key - Insert instead of update

I have this method in my service:
public function updateCountry($p_entity) {
var_dump($p_entity->getId()); //return 3 (as expected)
var_dump(get_class($p_entity) ); //return Country (as expected)
$this->em->persist($p_entity);
$this->em->flush();
}
I call it by
$country = $em->getRepository('blabla')->find(3);
$my_service->updateCountry($country);
But the request generated is
Doctrine\DBAL\DBALException: An exception occurred while executing
'INSERT INTO country (code, label , created_at, updated_at)
VALUES (?, ?, ?, ?)' with params ["EN", "England", "201
3-08-23 00:00:00", null]:
I have a unique doctrine constraint
this is my country.orm.yml
To\Bundle\Entity\Country:
type: entity
table: country
repositoryClass: To\Bundle\Entity\CountryRepository
fields:
id:
type: integer
id: true
generator:
strategy: AUTO
code:
type: string
length: 255
unique: true
nullable: false
Why have I an insert request generated instead of the update one?
Can you persist new entity at all?
If you can, try merging your object instead:
public function updateCountry($p_entity) {
var_dump($p_entity->getId()); //return 3 (as expected)
var_dump(get_class($p_entity) ); //return Country (as expected)
$this->em->merge($p_entity); // MERGE not PERSIST
$this->em->flush();
}
From official docs:
If X is a new entity instance, a new managed copy X’ will be created
and the state of X is copied onto this managed instance.
So, basically, EntityManager::merge can be used to both persist newly created object and merge exsistent one...
You shouldn't persist existing in DB entity, only new one.
So if you get entity from DB and want to update it
you should
$entity->setName()
$em->flush

Resources