Cosmos DB simple ID field for end user - azure-cosmosdb

Is it possible to include a user friendly ID field into cosmos db documents? This doesn't need to override the default id field that generates when adding a document but can be a custom one that is simple for an end user to know and search for.
Example document, the ref field is what I want to generate as a simple human readable identifier.
{
"id": "57275754475457-5445444-44420478",
"ref": "45H7GI",
"userId": "48412",
"whenCreated": "D2021-11-09T21:56:31.630",
"tenantId": "5566HH"
}
I'm looking at building a ticketing system and would like a simple ID field for a user to be sent and who can reference when updating/ searching for.
Any help with this would be appreciated.

For your own purposes, you can choose to either use id (which is guaranteed to be unique within a partition) or your own property (such as ref as you defined in your example). For any property other than id, you'd need to add a unique-key constraint when creating the container (and at that point, ref would be unique within any partition, just like id).
Really your choice whether you store your custom id's in id or ref. Just know that, if you ever want to do a direct-read (instead of a query), you can only do a direct-read against an id, not against any other property.

Related

Filter/some on list of objects in a Firestore security rule

In a Firestore security rule, I'm trying to check if the user attempting to create/delete a document in one collection is also the owner of that object, as marked in another collection. Basically, my data looks something like this:
In the users collection, each user has a document like this:
{
name: 'john',
userItems: [
{
id: 'random-id',
...
},
...
],
...
}
In the items collection (which I am writing the rule for), all of the items from all of the users of the platform are there, and have Firestore IDs which correspond to the id keys in the elements of the items list of their owners. So if john created an item with the id random-id, his user document would look like the above, and there would be a new document in the items collection with the Firestore ID of random-id.
What I am trying to achieve is to create a security rule wherein a document in the items collection can only be updated if the user document of the currently authed user, which I can access with get(/databases/$(database)/documents/users/$(request.auth.uid)), has an element in their userItems list which has the id key equal to request.resource.id. If this were normal JS, I'd probably do something like:
match /items/{item} {
allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid))
.data
.userItems
.some(userItem =>
userItem.id === request.resource.id
)
}
However, the Firestore List interface is very lacklustre, and doesn't support fancy operations like .some, or even basic/manual looping (as far as I'm aware). I've been trying to come up with some clever way around this, but even .joining the list and .matching the resulting string with some fancy RegExp wouldn't work, since I'm pretty sure that maps would parse as '[object Object]' instead of stringifying properly.
Is there any way to do this using standard Firestore rules, without reconfiguring my DB structure?
What you're trying to do isn't possible with security rules. You will need to either change that way you represent your data (which I recommend, as a list is probably not the best representation), or add more data to satisfy your requirements.
If the the random-id is unique in the list, you should consider using a map instead of a list to represent it, so that you can do simple lookups on the Map that becomes available in rules. If your userItems field was a map indexed by that ID, you could instead say:
allow write: if get(...).data.userItems.keys().hasAny([request.resource.id]);
If for some reason you can't change the field, you will need to duplicate the IDs into a new list field and check it like this:
allow write: if get(...).data.userItemIds.hasAny([request.resource.id]);

How to correctly define ID and DateTime fields in Firebase Firestore database?

I am using Firebase FireStore database for the first time and I have the following question.
I have created a calendar collection. This collection will contains document representing events that have to be shown into a Calendar implemented by an Angular application.
So I am defining the following fields for these documents:
id: int. It is a unique identifier of the specific document\event.
title: string. It is the event title.
start_date_time: string. It specifies the date and the time at which the event starts.
end_date_time: string. It specifies the date and the time at which the event ends.
And here I have some doubts:
Is the id field required? From what I know I will have the document UID that will ensure the uniqueness of the document. If not strongly required adopt an id field can be convenient have something like an auto increment field? (I know that I have to handle in some other way the auto increment because FireStore is not a relational DB and doesn't automatically handle it). For example I was thinking that can be useful to order my document from the first inserted one to the last inserted one.
It seems to me that FireStore doesn't handle DateTime field (as done for example by a traditional relational database). Is this assumption correct? How can I correctly handle my start_date_time and end_date_time fields? These field have to contains the date time used by my Angular application? So for example I was thinking that I can define it as string field and put into these fields values as 2020-07-20T07:00:00 representing a specific date and a specific time. It could be considered a valid approach to the problem or not?
Is the id field required?
No fields are required. Firestore is schema-less. The only thing a document requires is a string ID that is unique to the collection where it lives.
There is no autoincrement of IDs. That doesn't scale massively the way Firestore requires. If you need ordering, you will have to define that for yourself according to your needs.
In general, you are supposed to accept the randomly generated IDs that the Firebase client APIs will generate for you. Ordering is typically defined using a field in the document.
It seems to me that FireStore doesn't handle DateTime field
Firestore has a timestamp field type that stores moments in time to nanosecond precision. There is no need to store a formatted string, unless that's something you require for other reasons.

How can i generate custom IDs for objects in firebase?

Please I want to give custom IDs to my database objects in Firebase but I don't now how to do it. Firebase creates default IDs for database objects which I don't want. I want to be able to assign my own IDs to objects or the child nodes of in the database for unique identification.
Most likely you're adding the items to the database with something like:
ref.push().set("my value");
This generates a new unique key under ref and sets your value on it.
If you want to use you own key/name for the child location, add the item with:
ref.child("my key").set("my value");
You cannot customize ID of firebase object, but you can create another field with ID role.
ref.child("my_id").set("customize_id");
after that, using "Filter by key" to get exactly your object you want.
In our case: We need to have a user_id type Int and auto-increase, so we can't use default _id of firebase object, we create user_id ourself to solve this problem.

Is it possible to query an element in Firestore by key without knowing which collection it belongs to?

Using AngularFire2, Angular, Firebase Firestore, and one of my records models the relationship between a user and different types of objects.
/*
Represents a reaction that a user has towards some object in the system.
*/
export interface Reaction{
// The id of the user making that reaction
userId? : string;
// The id of the object that is being reacted to. Place, Org, List, Offer
objectId? : string;
}
As you can see the only thing being stored is the key of an object and not its type or which collection it belongs to. I'm wondering how it would be possible at a later time, to query the reactions and then from there get the objects purely based on their key?
You must know the name of the collection (and possibly subcollection) of a document in order to obtain it. There's no concept of a query that can get a document without knowledge of a collection.

How to entirely skip validation in simple schema and allow incomplete documents to be stored?

I'm creating an order form and a schema defined for an Order (certain required fields such as address, customer info, items selected and their quantities, etc).
a. User visits site.
b. A unique ID is generated for their session as well as a timestamp.
var userSession = {
_id: createId(),
timestamp: new Date(),
};
var sessionId = userSession._id;
c. The userSession is placed in local storage.
storeInLocalStorage('blahblah', sessionObject);
d. An Order object is created with the sessionId as the only field so far.
var newOrder = {
sessionId: sessionId;
};
e. Obviously at this point the Order object won't validate according to the schema so I can't store it in Mongo. BUT I still want to store it in Mongo so I can later retrieve incomplete orders, or orders in progress, using the sessionID generated on the user's initial visit.
This won't work because it fails validation:
Orders.insert(newOrder);
f. When a user revisits the site I want to be able to get the incomplete order from Mongo and resume:
var sessionId = getLocalStorage('blahblah')._id;
var incompleteOrder = Orders.findOne({'sessionId', sessionId});
So I'm not sure how to go about doing this while accomplishing these points.
I want full simpleschema validation on the Orders collection when the user is entering in items on the forms and when the user is intending to submit a full, complete order.
I want to disable simpleschema validation on the Orders collection and still allow storing into the DB so that partial orders can be stored for resumption at a later time.
I can make a field conditionally required using this here but that would mean 50+ fields would be conditionally required just for this scenario and that seems super cumbersome.
It sounds like you want to have your cake, and eat it too!
I think the best approach here would be keep your schema and validation on the Orders collection, but store incomplete orders elsewhere.
You could store them in another collection (with a more relaxed schema) if you want them on the server (possibly for enabling resume on another device for the logged in user) , or more simply in Local Storage, and still enable the resume previous order behaviour you are wanting.
Only write to the Orders collection when the order is complete (and passes validation).
Here's a variation on #JeremyK's answer: add an inProgress key to your order of type [Object]. This object would have no deeper validation. Keep your in progress order data in there until the order is final then copy/move all the relevant data into the permanent keys and remove the inProgress key. This would require that you make all the real keys optional of course. The advantage is that the object would maintain its primary key throughout the life cycle.
I think this particular case has been solved; but just in case, you can skip Simple Schemma validations by accessing MongoDB native API via Collection#rawCollection():
Orders.rawCollection().insert(newOrder);
While this question is very old in the meantime there is a better solution. You probably use simple schema together with collection2. Collection2 has the ability to set multiple schemas based on a selector and then validate against the correct schema based on it.
https://github.com/Meteor-Community-Packages/meteor-collection2#attaching-multiple-schemas-to-the-same-collection
e.g. you could have a selector {state: 'finished'} and only apply the full schema to these documents while having another selctor, e.g. {state: 'in-progress'} for unfinished orders with a schema with optional fields.

Resources