Realm react native schema versioning - react-native

I have the following 2 schemas in realm.js file
class Bill extends Realm.Object {}
Bill.schema = {
name: 'Bill',
primaryKey: 'id',
properties: {
id: { type: 'string', indexed: true },
year: 'int',
month: 'int',
description: 'string',
dateCreated: 'int',
}
};
class User extends Realm.Object {}
User.schema = {
name: 'User',
primaryKey: 'id',
properties: {
id: 'string',
name: 'string?',
email: 'string?'
}
};
const realm = new Realm({schema: [Bill, User]});
export default realm;
this works perfectly when I first release my app to AppStore or PlayStore.
I need to change both schema and release to AppStore or PlayStore again and I need to handle both new installation or update of my app where the schema change to following
class Bill extends Realm.Object {}
Bill.schema = {
name: 'Bill',
primaryKey: 'id',
properties: {
id: { type: 'string', indexed: true },
year: 'int',
month: 'int',
description: 'string',
dateCreated: 'int',
dateDeleted: 'int',
}
};
class User extends Realm.Object {}
User.schema = {
name: 'User',
primaryKey: 'id',
properties: {
id: 'string',
name: 'string?',
email: 'string?',
photoUrl: 'string?',
}
};
by adding one more field in each schema.
So how should I configure my realm schema version?
Should I configure like below:
const realm = new Realm([
{schema: Bill, schemaVersion: 1},
{schema: User, schemaVersion: 1}
]);
But this may crash for new installation.

You should set global schemaVersion for all database, not for each model. And perform migrations to the current version, like it's described in the docs:
You define a migration and the associated schema version by updating
the schemaVersion and defining an optional migration function. Your
migration function provides any logic needed to convert data models
from previous schemas to the new schema. When opening a Realm the
migration function will be applied to update the Realm to the given
schema version only if a migration is needed.
If no migration function is supplied then any new properties an
automatically added and old properties are removed from the database
when updating to the new schemaVersion. If you need to update old or
populate new properties when upgrading your version you can do this in
the migration function. For example, suppose we want to migrate the
Person model declared earlier. You can populate the name property of
the new schema using the old firstName and lastName properties:
Realm.open({
schema: [PersonSchema],
schemaVersion: 1,
migration: (oldRealm, newRealm) => {
// only apply this change if upgrading to schemaVersion 1
if (oldRealm.schemaVersion < 1) {
const oldObjects = oldRealm.objects('Person');
const newObjects = newRealm.objects('Person');
// loop through all objects and set the name property in the new schema
for (let i = 0; i < oldObjects.length; i++) {
newObjects[i].name = oldObjects[i].firstName + ' ' + oldObjects[i].lastName;
}
}
}
}).then(realm => {
const fullName = realm.objects('Person')[0].name;
});
Once the migration is successfully completed the Realm and all of its
objects can be accessed as usual by your app.

Related

Mongoose model schema referencing each other - how to simplify?

I am using mongoose and have two schemas: UserSchema and CommunitySchema:
const UserSchema = new Schema({
name: String,
communities: [{ type: Schema.Types.ObjectId, ref: CollectionModel }],
exCommunities: [{ type: Schema.Types.ObjectId, ref: CollectionModel }],
}, { timestamps: true });
const CommunitySchema = new Schema({
slug: { type: String, unique: true },
name: String,
description: String,
users: [
{ type: Schema.Types.ObjectId, ref: "User" }
]
}, { timestamps: true });
User can be a part of multiple communities and also leave any community and be in the exCommunities field.
When an user joins a community, I have to do a double work: Add the user to a user community and update the community user field with the reference ID.
Questions:
Is there a way to simplify it? For example, by managing the CommunitySchema users field automatically based on the UserSchema communities field?
Now I have to do this:
collection.users.push(userId);
user.communities.push(communityId);
Could the collection.users be automatically added when I push a community to user.communities? And how?)
Is it possible to add a date when the user is added to a community or leave a community? Something like: communities: [{ type: Schema.Types.ObjectId, ref: CollectionModel, createdAt: "<DATE>" }]
Thank you!
you no need to add communities and exCommunities in UserSchema
const UserSchema = new Schema({
name: String,
}, { timestamps: true });
const communityUserSchema = new Schema({
user_id:{type: Schema.Types.ObjectId, ref: "User"},
joined_at:{type:Date},
leaved_at:{type:Date},
is_active:{type:Boolean},
role:{type:String, enum:['user','admin'], default:'user'}
});
const CommunitySchema = new Schema({
slug: { type: String, unique: true },
name: String,
description: String,
users:{
type:[communityUserSchema],
default:[]
}
}, { timestamps: true });
you can find User's communities by :
let user_id = req.user._id;
all_communities = await Community.find({"users.user_id":user_id});
active_communities = await Community.find({"users.user_id":user_id, "is_active":true});
ex_communities = await Community.find({"users.user_id":user_id,"leaved_at":{"$ne":null}});
When User Create New Community (create as a Admin):
let current_user = {user_id:req.user.id,joined_at:new Date(),is_active:true,role:'admin'};
// if you select users from frontend while creating new community
let other_user = req.body.user_ids;
let other_users_mapped = other_user.map((item)=>{ return {user_id:item,joined_at:new Date(),role:'user',is_active:true}});
let all_users = [current_user];
all_users = all_users.concat(other_users_mapped);
let community = new Community();
community.name = req.body.name;
community.slug = req.body.slug;
community.description = req.body.description;
community.users = all_users ;
let created = await community.save();
When User Leave Community :
Community.updateOne({_id: community_id , 'users.user_id':user_id },{
$set:{
'users.$.is_active':false,
'users.$.leaved_at':new Date()
}
});
View Community with only active members :
let community_id = req.params.community_id;
let data = await Community.findOne({_id:community_id},{ users: { $elemMatch: { is_active: true } } });
AI solved it for me, here is the correct example:
import * as mongoose from 'mongoose';
const Schema = mongoose.Schema;
interface User {
name: string;
email: string;
communities: Community[];
}
interface Community {
name: string;
description: string;
users: User[];
}
const userSchema = new Schema({
name: String,
email: String,
}, {
timestamps: true,
});
const communitySchema = new Schema({
name: String,
description: String,
}, {
timestamps: true,
});
// Define the user_communities table using the communitySchema
const userCommunitySchema = new Schema({
user: { type: Schema.Types.ObjectId, ref: 'User' },
community: { type: Schema.Types.ObjectId, ref: 'Community' },
joined_on: Date,
}, {
timestamps: true,
});
// Use the userCommunitySchema to create the UserCommunity model
const UserCommunity = mongoose.model('UserCommunity', userCommunitySchema);
// Use the userSchema to create the User model, and define a virtual property
// for accessing the user's communities
userSchema.virtual('communities', {
ref: 'Community',
localField: '_id',
foreignField: 'user',
justOne: false,
});
const User = mongoose.model<User>('User', userSchema);
// Use the communitySchema to create the Community model, and define a virtual property
// for accessing the community's users
communitySchema.virtual('users', {
ref: 'User',
localField: '_id',
foreignField: 'community',
justOne: false,
});
const Community = mongoose.model<Community>('Community', communitySchema);
The userSchema and communitySchema are then used to create the User and Community models, respectively. For the User model, a virtual property called communities is defined using the virtual method. This virtual property is used to specify how to populate the user.communities property when querying the database. The communitySchema also defines a users virtual property, which is used to populate the community.users property when querying.

How to store an Array of Arrays with Realm in React Native?

I want to store an array of arrays using Realm, but if I use type mixed it throws an error:
[Error: A mixed property cannot contain an array of values.]
This is my sample code:
export const ContentScheme = {
name: 'content',
primaryKey: 'elementId',
properties: {
elementId: 'string?',
currentTimeInfo: 'mixed',
}
}
Inserting Data:-
let data = {
elementId: '60d19799c0023702d41c1110',
currentTimeInfo:[["03.41", "03.29"], ["03.30", "05.14"], ["05.18", "00.00"]]
}
For my approach, I will create another schema CurrentTimeSchema and store it as array in ContentSchema.
Here is the solution.
export const ContentScheme = {
name: 'content',
primaryKey: 'elementId',
properties: {
elementId: 'string?',
currentTimeInfo: 'CurrentTime[]', <-- store CurrentTime in []
}
}
export const CurrentTimeSchema = {
name: 'CurrentTime',
embedded: true, <-- avoid creating new object of CurrentTime
properties: {
time1: 'string?', <-- rename these
time2: 'string?',
}
};

RealmJS:How to write sorted fetch query where inner object is Key-Value?

Product has many details like: productName, manufactured date, manufacturer name, product type etc. But I need to support flexibility of having no defined schema for product details. To achieve this below is the Realm-JS schema.
import Realm from 'realm';
export default class ProductModel extends Realm.Object { }
ProductModel.schema = {
name: 'ProductModel',
properties: {
productAttributes: { type: 'list', objectType: 'ProductDetailsModel' },
ID: { type: 'string', optional: true },
}
};
import Realm from 'realm';
export default class ProductDetailsModel extends Realm.Object { }
ProductDetailsModel.schema = {
name: 'ProductDetailsModel',
properties: {
attributeName: { type: 'string', optional: true },
attributeValue: { type: 'string', optional: true },
}
};
This flexibility is yielding in complexity of writing sort query. I need to be able to sort based on Product Attribute values. Let us say 'Product Name' is on attribute of Product, I need to fetch Product sorted by 'Product Name' in 'A-Z' or reverse order.
var productList = realm.objects('ProductModel').sorted(<Some query string>)
Please help me to write query to fetch the ProductModel from DB based on some values(productName or manufacturer name etc..) sorted order?
P.S. Other option which I am aware is get the realm objects and sort using Array.sort.
Update 1:
When I try to do sort with below query:
let item = this.realm.objects('ProductModel').filtered("productAttributes.attributeName = " + "\"" + "serialNo" + "\"")
.sorted('productAttributes.attributeValue', false);
I am getting below error
Cannot sort on key path 'productAttributes.attributeValue': property 'ProductModel.productAttributes' is of unsupported type 'array'.

Realm React Native: How remove element from object's nested array with some condition

I am new in React native and trying to integrate Realm as a client side DB.
I have 2 schemas:
export const CAR_SCHEMA = {
name: 'Car',
properties: {
color: 'string',
model: 'string',
}
};
export const PERSONS_SCHEMA = {
name: 'Person',
primaryKey: 'id',
properties: {
id: 'int',
firstName: 'string',
lastName: 'string'
cars: 'Cars[]'
}
};
My question basically means how to remove 'Car' from 'Person' where Car.model='Honda'? I couldn't find any documentation about deleting element from object's nested array.
Remove from array but keep item in Realm:
realm.write(() => {
let person = realm.objectForPrimaryKey('person', personId);
let carsOfPerson = person.cars;
var i = carsOfPerson.length - 1;
while(i >= 0) {
if(carsOfPerson[i].model == "Honda") {
carsOfPerson.splice(i, 1);
}
i--;
}
});
Remove from array by deleting item from Realm:
realm.write(() => {
let person = realm.objectForPrimaryKey('person', personId);
let carsOfPerson = person.cars;
let hondasOfPerson = carsOfPerson.filtered('model = "HONDA"')
realm.delete(hondasOfPerson)
});

Realm does not seems to working

I am trying to use realm in react-native android and I just wanted to test if it is working or not.
It seems to save data since it throws duplicated primaryKey error.
However, realm.objects('Person') does not return data but
Proxy
[[Handler]]
:
Object
[[Target]]
:
Results
[[IsRevoked]]
:
false
class Person {}
Person.schema = {
name: 'Person',
primaryKey: 'name',
properties: {
name: 'string',
age: {type: 'int', default: 0},
},
};
const realm = new Realm({schema: [Person],schemaVersion: 2});
// Write
realm.write(() => {
const savedPerson = realm.create('Person', {
name: 'Hal Incanden1za',
age: 17,
});
});
console.log(realm.objects('Person'))
The value you get from a realm.objects() call is not a normal array, so console.log may not be doing what you are expecting here. Try iterating through it instead.