Flutter Isar String ID - flutter

My app have String ID for all entities (Server side) I want migrate from Hive to Isar so I was reading the Isar documentation and find out it doesn't support String ID (only int), Yes I know that I can create a Class like this:
#Collection()
class Student {
int? id;
#Index(unique: true)
String? myServerId;
late String name;
final teacher = IsarLink<Teacher>();
}
When I fetch data (JSON) from server the id field (manager for Isar) don't came from server, so I save this record local Isar will create the ID OK, next time I get the same record from server is needed check via myServerId and if exist just update with id created by Isar its easy, how I can manager its with all entities filds like teacher? Need check every entities child or have a better way? Thanks in advance

set replace to true in #Index of myServerId,
like this:
#Collection()
class Student {
int? id;
#Index(unique: true , replace:true)
String? myServerId;
late String name;
final teacher = IsarLink<Teacher>();
}
check this Isar Replace indexes Doc.

Related

How to query entities using backlink in ObjectBox with flutter

This is my first time working with objectBox. I have unfortunately stumbled on this issue and I failed to solve it.
I have two entities Product and Order as below.
#Entity()
class Customer{
int id;
String name;
#Backlink()
final orders = ToMany<Order>();
Customer({
this.id = 0,
required this.name,
});
}
#Entity()
class Order{
int id;
String? orderNumber;
final customer = ToOne<Customer>();
Order({
this.id = 0,
this.orderNumber,
});
}
A customer can place many orders but an order can only be placed by one customer.
I believe a list of all the orders for a specific customer can be returned simply by;
customer.orders;
But I would like to return a stream of all the orders made by a specific customer to feed into a streamBuilder. something like Stream<List<Order>>.
I have tried to read through the objectBox docs and I see I have to do something with backlink but I have failed to make it work. I would be very greatful for any help here.
Try to create and watch a link query, e.g. something like
final builder = store.box<Order>().query()
builder.link(Order_.customer, Customer.id.equals(customerId));
Stream<Query<Order>> ordersByCustomer = builder.watch();
Source/Details: https://docs.objectbox.io/queries#add-query-conditions-for-related-entities-links

How to get last record in spring mongo?

I have a transaction class which stores the each transaction of a customer,Following are the fields in this class.
class Transaction{
#Id
private String id;
private Date date;
private String customerId;
private double openBalance;
private double transctionAmount;
private double finalAmount;
}
I need to fetch only the last inserted record of a customer (let say for customerId = cust123).
I defined following function in repository.
public interface TranscationRepository extends MongoRepository<Transaction, String> {
Optional<Transaction> findTopByCustomerIdOrderByIdDesc(String id);
}
This method giving last entry not by customerId but overall. I tried few modifications to it but did not get success.
I know I can findAllByCustomer but I don't want to pull huge list of transaction which is of no use in this use case. What is correct signature in spring mongo to get last inserted record by a field? I am ok to use custom #Query also.
Thank you.

Designing mongodb schema with searchable nested arrays.

I'm new to Mongodb coming from relational databases and I'd also like to point out I'm using SpringBoot with JPA. If I were to build an automotive classified site where I would have thousands of Users and 100s of thousands of listings, how would I go about setting up the schema? I've read some articles that say normalizing nosql data is bad practices.
Anyhow lets say we have the following structure.
User
id
name
email
Cars
id
make
model
year
I would need to be able to list many cars with the User and what i've seen in my examples is it creates a nested array of cars within User. This would work great for user accounts where I'd like to provide the user with all their cars
Where I get a bit confused is with the cars. The cars need to be able to be searched very quickly and would not need the user info right away. In a sql db I would typically do a search against the cars (year, make, model) and grab the user later on if I needed it.
In mongodb, do you create a User document that contains a nested car array? or do you somehow create 2 documents that are both automatically maintained and search against the car document for performance reasons?
Sample code
#Document(collection = "person")
public class Person {
#Id
private String id;
private String firstName;
private String lastName;
// #DBRef(lazy = true)
private List<Listing> listings;
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
#Document(collection = "listing")
public class Listing {
#Id
public String id;
public String year;
public String make;
public String model;
public String trim;
public Listing(String year, String make, String model, String trim) {
this.year = year;
this.make = make;
this.model = model;
this.trim = trim;
}
}
#Override
public void run(String... args) throws Exception {
repository.deleteAll();
List<Listing> listings = new ArrayList<>();
Listing listing = new Listing("2008", "Ford", "Focus", "SE");
//listingRepository.save(listing);
listings.add(listing);
Person person = new Person("Alice", "Smith");
person.setListings(listings);
// save a couple of customers
repository.save(person);
person = new Person("Bob", "Smith");
listings = new ArrayList<>();
listings.add(new Listing("2018", "Chrysler", "300", "S"));
person.setListings(listings);
repository.save(person);
// fetch all customers
System.out.println("Customers found with findAll():");
System.out.println("-------------------------------");
for (Person _person : repository.findAll()) {
System.out.println(_person);
}
System.out.println();
// fetch an individual customer
System.out.println("Person found with findByFirstName('Alice'):");
System.out.println("--------------------------------");
System.out.println(repository.findByFirstName("Alice"));
System.out.println("Persons found with findByLastName('Smith'):");
System.out.println("--------------------------------");
for (Person _person : repository.findByLastName("Smith")) {
System.out.println(_person);
}
List<Listing> _listings = listingRepository.findAll();
System.out.println("listings " + _listings.size());
_listings.forEach(v -> {
System.out.println(v.toString());
});
}
Going by your entity model,I think what you are looking for is analogous to Many to Many/One to Many relationship in a relational database. So you can go for One way Embedding or Two way Embedding in MongoDb.
For One way embedding, You can create a Car collection like below:
db.carCollection.insertMany([{
_id:1,
make: 'porcha',
model:'qwerty',
year:'2018'
},
{
_id:2,
make: 'ferrara',
model:'uiop',
year:'2018'
}])
You can then go on to create user collection as below:
db.userCollection.insert({
_id:1,
user:'Tom',
email:'tom#tom.com',
car_ids:[1,2]
})
The car_ids is an array which will hold the ids of cars that belong to the user.
You can fetch the cars belonging to an user as(using findOne to fetch the user. Search parameter should be an unique id. I am considering email to be unique here.Ideally it should be user's id) :
var user=db.userCollection.findOne({email:'tom#tom.com'})
db.carCollection.find({_id:{$in:user.car_ids}})
This will fetch you all the cars per user
For fetching cars only you can simply do:
db.carCollection.find({})
For Two way embedding you can have similar array (as in user collection) inside cars collection so that each car can be identified to its user.

Morphia (MongoDB) Datastore "get" returns null

So I started working with Morphia and I'm encountering a weird problem.
Here's my entity class
#Entity("movies")
#Indexes(#Index(value = "Name", fields = #Field("Name")))
#Converters(LocalDateConverter.class)
public class MovieDetails implements Serializable
{
#Id
public String Id;
public String Name;
public String Description;
public String ImageName;
public LocalDate ReleaseDate;
public String Director;
public int Duration;
public String Genres;
public String Actors;
public MovieDetails()
{
}
public MovieDetails(String id, String name, String description, String imageName, String director, String actors, LocalDate releaseDate, String genres, int duration)
{
this (name, description, imageName, director, actors, releaseDate, genres, duration);
Id = id;
}
public MovieDetails(String name, String description, String imageName, String director, String actors, LocalDate releaseDate, String genres, int duration)
{
Name = name;
Description = description;
ImageName = imageName;
Director = director;
Actors = actors;
ReleaseDate = releaseDate;
Genres = genres;
Duration = duration;
}
}
Here's my little test:
final Morphia morphia = new Morphia();
// tell Morphia where to find your classes
// can be called multiple times with different packages or classes
morphia.mapPackage("nimrodpasha.cinema.objects");
// create the Datastore connecting to the default port on the local host
final Datastore datastore =
morphia.createDatastore(SingleMongoClient.getInstance().getClient(),
Constants.DB.TICKET_DATABASE);
datastore.ensureIndexes();
//region new movie
MovieDetails movie = new MovieDetails("The Mask", "Stanley Ipkiss (Jim Carrey) is a bank clerk that is an incredibly nice man. Unfortunately," +
" he is too nice for his own good and is a pushover when it comes to confrontations. After one of the worst days of his life, he finds a mask that depicts Loki, " +
"the Norse night god of mischief. Now, when he puts it on, he becomes his inner, self: a cartoon romantic wild man. However, a small time crime boss, Dorian Tyrel (Peter Greene), " +
"comes across this character dubbed The Mask by the media. After Ipkiss's alter ego indirectly kills his friend in crime," +
" Tyrel now wants this green-faced goon destroyed.",
"MASK.jpg", "Chuck Russell", "Jim Carrey as Stanley Ipkiss/The Mask,Cameron Diaz as Tina Carlyle,Amy Yasbeck as Peggy Brandt,Joely Fisher as Maggie", new LocalDate(1994, 2, 1), "Action,Comedy,CrimeAction,Family,Fantasy", 88);
//endregion
// Clearing the db first
datastore.delete(datastore.createQuery(MovieDetails.class));
// Saving a new entity and getting the result saved id
String id = (String) datastore.save(movie).getId();
// This returns as null
MovieDetails movieRetrieved = datastore.get(MovieDetails.class, id);
// This returns with one item
List<MovieDetails> allMovies = datastore.createQuery(MovieDetails.class).asList();
When I use
datastore.get(MovieDetails.class, id)
I get null
When I use:
datastore.createQuery(MovieDetails.class).asList();
I do see my movie in the DB, with the Id used in the get function.
Tried the id in many variations... toString(), ObjectId(id), Key (The value returned from the save result).
The Id in the DB (viewed with Mongo Explorer) does show as something which isn't string (blue colored), suspicious:
Mongo Explorer item picture
Any ideas?
Edit:
* the Id is indeed a string, the cast works and it was verified using watch + instanceof
Edit 2:
* Somehow the cast from ObjectId to String passed and the Id wasnt really a String.
I would change your I'd field from String to a BSON ObjectId field which MongoDB will automagically assign on save. If you then do your get call with the ObjectId as the parameter, it should work. Using ObjectId as your ID field is highly recommended with Mongo.
I am guessing that Morphia is trying to marshall an ObjectId into your String Id field and there is a small bug somewhere. I would try calling datastore.get(Example.class, new ObjectId(id)).
After Nic Cottrell (Thanks!) answer I've had a new perspective of the problem.
As my #Id field was not assigned by me it was automaticaly assigned in the DB as ObjectId.
As I still want to use String I've simply assigned the #Id field on object creation.
Id = ObjectId.get().toString();
found the solution on:
MongoDB / Morphia saves technical id as ObjectId although it's a String in Java

Spring mongodb get ID of inserted item after Save

I am working with Spring MongoDb.
I create various entities using insert method:
http://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/core/MongoOperations.html#insert-java.lang.Object-
However, all methods return void. I need to return the ObjectId of the inserted document.
What is the best way to get it?
This is pretty interesting and thought I would share. I just figured out the solution for this with the help of BatScream comment above:
You would create an object and insert it into your MongoDB:
Animal animal = new Animal();
animal.setName(name);
animal.setCat(cat);
mongoTemplate.insert(animal);
Your animal class looks like this with getters and settings for all fields:
public class Animal {
#Id
#JsonProperty
private String id;
#JsonProperty
private String name;
#JsonProperty
private String cat;
public String getId() {
return id;
}
}
AFTER you have done the insert under mongoTemplate.insert(animal);, you can actually call the method animal.getId() and it will return back the ObjectId that was created.
I had the same problem with #AlanH that animal.getId() is null. And then I just realized my id field had been set as a final field with a wither method. So of course getId() is null since the id field is immutable and the wither method returns a new object with id.
if this is the case: use animal = template.insert(animal).