Realm - Creating and Updating Objects With other Keys apart from primary key - realm

I'm using Mongodb Realm.
I know it is possible to 'createOrUpdate' in realm by using the primary key i.e If the primary key doesn't exists create a new object, If it does update the object.
Something like
realm.write(() => {
// Create a book object
realm.create('Book', {id: 1, date: '12-12-2020', price: 35});
// It will update the price but won't create a new object since the id is the same
realm.create('Book', {id: 1, date: '12-12-2020', price: 55}, 'modified');
});
The realm docs says that
If your model class includes a primary key, you can have Realm
intelligently update or add objects based off of their primary key
values. This is done by passing true as the third argument to the
create method:
this can be found here https://docs.mongodb.com/realm-legacy/docs/javascript/latest/#creating-and-updating-objects-with-primary-keys
NOW, I want to update the Object based on a different field(key) apart from the primary key and On this case it is the date field This is to say that, If the date doesn't exist, create a new object/entry but it it does, just update the price.
How do I do this with realm?

Related

DynamoDB secondary index is not unique?

I have set a secondary index with only a partition key (without a sort key), but I found that actually I can insert multiple items with the same partition key.
If I issue a query using the partition key in the secondary index, I'll get all the items where the partition key is equal to the given partition key value.
I'm a beginner of DynamoDB, I want to know if set a secondary index with only a partition key, but insert multiple items with the same partition key is a good idea.
I'm using Amplify.js and have this GraphQL schema:
type UserMeta #model #key(fields: ["owner"]) #auth(rules: [
{ allow: owner, operations: [create, delete, update] },
{
allow: groups,
groups: ["Admins"],
operations: [update, delete]
}
]) {
familyName: String
givenName: String
facebookUrl: AWSURL
twitterUrl: AWSURL
description: String
careers: [Career] #connection(keyName: "byOwner", fields: ["owner"])
owner: String!
}
type Career #model #key(name: "byOwner", fields: ["owner"]) #auth(rules: [
{ allow: owner, operations: [create, delete, update] },
{
allow: groups,
groups: ["Admins"],
operations: [update, delete]
}
]) {
id: ID!
company: String
companyUrl: AWSURL
industry: String
occupation: String
owner: String!
}
as you can see, the Career table has a secondary index byOwner with a partition key associated with owner(no sort key). but I can query the careers of a UserMeta normally.
with a traditional RDBMS, the index column can not be the same, I don't know why this is possible in DynamoDB, is this a best practice in DynamoDB??
Should I set a sort key for the byOwner index? maybe the sort key can be the id column?
with a traditional RDBMS, the index column can not be the same, I
don't know why this is possible in DynamoDB, is this a best practice
in DynamoDB??
Every RDBMS I've worked with allows both both unique and non-unique indexes.
The only uniqueness available in DDB is for the table's primary key.
It's very common to have records with the same partition key. In the table, records with the same partition key must have a different sort key.
For indexes, duplicates are allowed and again, this is very common use case.
One difference between RDBMS and DynamoDB is the latter expects you to know your data access patterns and use that to inform what shape the data should take. So this question ...
Should I set a sort key for the byOwner index? maybe the sort key can be the id column?
... can only be answered by knowing how you plan to load the Career objects.
If you're going to use a GraphQL query that only ever loads one at a time, like ...
type Query {
career(owner: String!, id: Id!)
}
... then adding the ID as a sort key is well worth it. It would mean the GraphQL Resolver for a Career will always be able to retrieve exactly the right object each time.
But if you'll need queries that will get a list of Career objects ...
type Query {
careers(owner: String!, since: dateString)
}
... and by default you only want to retrieve something like the "most recently created careers", then you would be better served by creating another attribute tracking when the career was created -- say createdAt: String! -- and use that as the sort key. The Resolver would then receive the list of careers by that owner in a logical sequence, allowing it to only read the oldest (or newest) careers.
This answer has some related info on how to use GSI's and sort keys with AWS AppSync.

Dynamoose model update with hash key

I'm trying to execute an update against a dynamoose model. Here's the docs on calling model.update
Model.update(key[, updateObj[, settings]],[ callback])
key can be a string representing the hashKey or an object containing the hashKey & rangeKey.
My schema has both a hash key (partition key) and range key (sort key) like this:
// create model
let model = dynamoose.model(
"SampleStatus",
{
id: {
type: String,
hashKey: true,
},
date: {
type: Date,
rangeKey: true,
},
status: String,
});
I've created an object like this (with a fixed timestamp for demoing)
let timestamp = 1606781220842; // Date.Now()
model.create({
id: "1",
date: new Date(timestamp),
status: "pending",
});
I'd like to be able to update the status property by referencing just the id property like this:
model.update({id: "1"}, {status: "completed"})
// err: The provided key element does not match the schema
model.update("1", {status: "completed"})
// err: Argument of type 'string' is not assignable to parameter of type 'ObjectType'
But both result in the shown errors:
I can pass in the full composite key if I know the timestamp, so the following will work:
let timestamp = 1606781220842; // Date.Now()
model.update({ id: "1", date: timestamp }, { status: "completed" });
However, that requires me holding onto the timestamp and persisting alongside the id.
The ID field, in my case, should, by itself, be unique, so I don't need both to create a key, but wanted to add the date as a range key so it was sortable. Should I just update my schema so there's only a single hash key? I was thinking the docs that said a "`key can be a string representing the hashkey" would let me just pass in the ID, but that throws an error on compile (in typescript).
Any suggestions?
The solution here is to remove the rangeKey from the date property.
This is because in DynamoDB every document/item must have a unique “key”. This can either be the hashKey or hashKey + rangeKey.
Since you mention that your id property is unique, you probably want to use just the hashKey as the key, which should fix the issue.
In your example there could have been many documents with that id, so DynamoDB wouldn’t know which to update.
Don’t forget that this causes changes to your table so you might have to delete and recreate the table. But that should fix the problem you are running into.
Logically there is nothing stopping you than inserting more than 1 entry into the same partition (in your case the unique id). You could insert more than one item with the same id, if it had a different date.
Therefore if you want to get an item by only its partition key, which is really a unique ID, you need to use a query to retrieve the item (as opposed to a GET), but the return signature will be a collection of items. As you know you only have one item in the partition, you can take the first item, and specify a limit of 1 to save RCU.
// create model
let model = dynamoose.model(
"SampleStatus",
{
id: {
type: String,
hashKey: true,
"index": {
"name": "index_name",
"rangeKey": "date",
}
},
date: {
type: Date
},
status: String,
});
You have to tell the schema that hashKey and range are one partition key.
Ref: https://dynamoosejs.com/guide/Schema#index-boolean--object--array

firebase - pushing an object to an array angularFire2

I have a db in which I want to store data like this:
Books:
0:{pushed Object}
1:{pushed object} ...
As if it is an arrays so I can iterate over it and do the stuff I need to do. The problem is that I am storing data as pic related shows:
pic related
It is storing the object with the push_ID firebase assigns to an object but not with the index of an array. This is how I am pushing the object to my database:
let book_data = {
id: bookId,
name: bookData.name,
author: bookData.author,
genre: bookData.genre,
publishDate: bookData.publishDate
};
this.fb.list(`my-lists/${bookList.name}/books/`).push(bookData);
What am I doing wrong?
If needed, I'm coding this for an ionic project.
If you use push() method, Firebase assign it a unique ID without you doing anything else. so if you want a custom key that you defined, you can use set() to save data to a specified reference, also it can be replacing any existing data at that path.
let book_data = {
id: bookId,
name: bookData.name,
author: bookData.author,
genre: bookData.genre,
publishDate: bookData.publishDate
};
let yourkey = 0;
this.fb.list(`my-lists/${bookList.name}/books/${yourkey}`).set(bookData);
When you set new object next time, you have to change the key again and save data

Objects with multiple key columns in realm.io

I am writing an app using the Realm.io database that will pull data from another, server database. The server database has some tables whose primary keys are composed of more than one field. Right now I can't find a way to specify a multiple column key in realm, since the primaryKey() function only returns a String optional.
This one works:
//index
override static func primaryKey() ->String?
{
return "login"
}
But what I would need looks like this:
//index
override static func primaryKey() ->[String]?
{
return ["key_column1","key_column2"]
}
I can't find anything on the docs on how to do this.
Supplying multiple properties as the primary key isn't possible in Realm. At the moment, you can only specify one.
Could you potentially use the information in those two columns to create a single unique value that you could use instead?
It's not natively supported but there is a decent workaround. You can add another property that holds the compound key and make that property the primary key.
Check out this conversation on github for more details https://github.com/realm/realm-cocoa/issues/1192
You can do this, conceptually, by using hash method drived from two or more fields.
Let's assume that these two fields 'name' and 'lastname' are used as multiple primary keys. Here is a sample pseudo code:
StudentSchema = {
name: 'student',
primaryKey: 'pk',
properties: {
pk: 'string',
name: 'string',
lastname: 'string',
schoolno: 'int'
}
};
...
...
// Create a hash string drived from related fields. Before creating hash combine the fields in order.
myname="Uranus";
mylastname="SUN";
myschoolno=345;
hash_pk = Hash( Concat(myname, mylastname ) ); /* Hash(myname + mylastname) */
// Create a student object
realm.create('student',{pk:hash_pk,name:myname,lastname:mylastname,schoolno: myschoolno});
If ObjectId is necessary then goto Convert string to ObjectID in MongoDB

Meteor update array of objects

I'm using Schema with this Meteor project. I've got an array of objects in the Schema, which I create them this way:
'milestones.$.name'
I create some properties like this, and allow for dynamic insert.
Now, I want to grab a milestone by name from milestones array and update some of its properties.
How can I do this?
I'm trying this at the moment, but still no positive result:
Projects.update(
{_id: currentPostId, 'milestones.name':this.name},
{$set: {'milestones.$': {name: this.name, hours: this.hours, complete:true}}}
);

Resources