Are Parse IDs deterministic? - mongodb

I know that in Mongo, when you create IDs, the IDs are created in part by a time element which can be nice for sorting without using any other keys like createdAt or updatedAt. Is the same true for IDs created in Parse?

Parse-server doesn't use deterministic IDs for the object but 10 characters random strings (which can be configured on your side also if you wish to have longer objectIds)
https://github.com/parse-community/parse-server/blob/master/src/cryptoUtils.js#L39

Related

MongoDB ObjectId vs string in find()

I'm starting to play with mongodb, and I learned that when inserting a document, you can either provide an ID, or let mongodb generate it for you.
I thought this is nice, because I want to let my users optionally choose an id, and if not generate it for them.
But the problem is, the generated one is of type ObjectId while the user provided one is a string, and the find method only returns the correct answer if you pass it with the correct type. So when a user requests GET /widget/123, I have no idea if the original ID was stored as an ObjectId or a string do I?
So how am I supposed to use this feature?
First off, I'd recommend against letting users provide _ids: if 2 users want to use the same _id, the second user will be unable to, which will be frustrating. If users want that functionality, I'd recommend storing the user created id on a separate field & querying by user (or company or whatever) and the user-created id.
That said, mongo ObjectIds are 24 hex characters, so you can safely identify when an id is not a MongoId by checking whether it doesn't match /^[a-f0-9]{24}$/ (or by seeing whether a call to ObjectId("maybeAnObjectId") throws). In the case where it's unclear (where a user might have provided 24 hex characters as their id), you'll need to use $in (or $or) to query for both cases:
const query = /^[a-f0-9]{24}$/.test(id) ? { _id: {$in: [ObjectId(id), id]}} : {_id: id}
(an annoying user could re-use an autogenerated ObjectId as their string id, and then queries to that route would return two values and there'd be no way of differentiating them).

What is the optimal way of querying array with a lot of objectIds

I have an array of MongoDB Object IDs which I want to send to my nodejs server in order to get the objects' data.
The problem is that this array contains hundreds of IDs and I am not sure how should I fetch and query it as concatenating it to the query string will not do as the maximal URL can have up to 2048 characters.
You can do the following things:
If records in DB ordered by _id
Send an array of Ids in the POST request or send Min and max Id only in the query parameter in the GET request.
Instead, query for individual Id(objectId) or doing {$in : [ObjectId( )... ObjectId.....]} do as mentioned in below point.
Using min and max id from an array, query DB like this:
User.find({"_id":{$lte: idmax,$gte:idmin}})
If records are not ordered on _id:
User.find({"_id":{$in:[_id1,id_2.....]})
PS: Learn more about range queries.
The relationship between the order of ObjectId values and generation
time is not strict within a single second. If multiple systems, or
multiple processes or threads on a single system generate values,
within a single second; ObjectId values do not represent a strict
insertion order. Clock skew between clients can also result in
non-strict ordering even for values, because client drivers generate
ObjectId values, not the mongod process. So if this is a case you will
have to query using in operator {$in : [ObjectId( ). ObjectId.....]}
Long story short: If ids are not in the order in DB you will have to use
the in operator because otherwise, the range query will fetch
extra-record.

Does length of indexed field matter while searching?

The chat app schema that I have is something like below.
1. conversations {participants[user_1, user_2], convsersation_id}
2. messages {sender: user_1, sonversation_id, timestamps}
I want to map this relationship using existing _id:ObjectId which is already indexed.
But if I want to get all conversation of user_1 I have to first search in which conversation that user is involed and get that conversation's _id and again search for the messages in messages using that conversation _id.
So my questions are -
Does length of indexed field (here _id) matters while searching?
Should I create another shorter indexed fields?.
Also if there is any better alternative schema please suggest.
I would suggest you to maintain the data as sub documents instead of array. The advantage you have is you can build another index (only) on conversation_id field, which you want to query to know the user's involvement
When you maintain it as array, you cannot index the converstaion_id field separately, instead you will have to build a multi key index, which indexes all the elements of the array (sender and timestamps fields) which you are never going to use for querying and it also increases the index size
Answering you questions:
Does length of indexed field (here _id) matters while searching? - Not really
Should I create another shorter indexed fields? - Create sub-document and index converstaion_id
Also if there is any better alternative schema please suggest. - Maintain the array fields as sub-documents

Find documents with a certain field value only when another field value is a given string

I'm using this php package to make queries - https://github.com/jenssegers/laravel-mongodb
The situation is, there are two fields, user_id and post_status among others. I want to retrieve all the documents in that collection, but when post_status field value is draft, that should be retrieved only when user_id is a given string. The idea is, only logged in user finds their drafted posts among other posts.
I'm having hard time finding any solution for this problem. The app is still not in production. If I should store data is some different manner, that is an option as well.
Find documents with a certain field value only when another field value is a given string
The question your are framing is simply convert into a and query, how let's see it
when another field value is a given string
This means that you have some result sets and you need to filter out when user_id match with some string. i.e some result sets and user_id = <id>
Now consider the first part of the sentence Find documents with a certain field value
This means you are filtering the records with some values i.e "status" = "draft" and whatever result will come and want again to filter on the basis of user_id = <id>
So finally you will end-up with below query:
db.collectionName.find({"status":"draft", "user_id": "5c618615903aaa496d129d90"})
Hope this explanation will help you out or you can rephrase your question I will try to modify by ans.

Firestore order by time but sort by ID

I have been trying to figure out a way to query a list of documents where I have a range filter on one field and order by another field which of course isn't possible, see my other question: Order by timestamp with range filter on different field Swift Firestore
But is it possible to save documents with the timestamp as id and then it would sort by default? Or maybe hardcode an ID, then retrieve the last created document id and increase id by one for the next post to be uploaded?
This shows how the documents is ordered in the collection
Any ideas how to store documents so they are ordered by created at in the collection?
It will order by document ID (ascending) by default in Swift.
You can use .order(by: '__id__') but the better/documented way is with FieldPath documentID() I don't really know Swift but I assume that it's something like...
.order(by: FirebaseFirestore.FieldPath.documentID())
JavaScript too has an internal variable which simply returns __id__.
.orderBy(firebase.firestore.FieldPath.documentId())
Interestingly enough __name__ also works, but that sorts the whole path, including the collection name (and also the id of course).
If I correctly understood your need, by doing the following you should get the correct order:
For each document, add a specific field of type number, called for example sortNbr and assign as value a timestamp you calculate (e.g. the epoch time, see Get Unix Epoch Time in Swift)
Then build a query sorted on this field value, like:
let docRef = db.collection("xxxx")
docRef.order(by: "sortNbr")
See the doc here: https://firebase.google.com/docs/firestore/query-data/order-limit-data
Yes, you can do this.
By default, a query retrieves all documents that satisfy the query in
ascending order by document ID.
See the docs here: https://firebase.google.com/docs/firestore/query-data/order-limit-data
So if you find a way to use a timestamp or other primary key value where the ascending lexicographical ordering is what you want, you can filter by any fields and still have the results sorted by the primary key, ascending.
Be careful to zero-pad your numbers to the maximum precision if using a numeric key like seconds since epoch or an integer sequence. 10 is lexicographical less than 2, but 10 is greater than 02.
Using ISO formatted YYYY-mm-ddTHH:MM:SS date-time strings would work, because they sort naturally in ascending order.
The order of the documents shown in the Firebase console is mostly irrelevant to the functioning of your code that uses Firestore. The console is just for browsing data, and that sorting scheme makes it relatively intuitive to find a document you might be looking for, if you know its ID. You can't change this sort order in the console.
Your code is obviously going to have other requirements, and those requirements should be coded into your queries, without regarding any sort order you see in the dashboard. If you want time-based ordering of your documents, you'll have to store some sort of timestamp field in the document, and use that for ordering. I don't recommend using the timestamp as the ID of a document, as that could cause problems for you in the future.