Firebase Invalid document reference. Document references must have an even number of segments - node.js

What is wrong with this query?
const db = firebase.firestore()
const query = db.doc(this.props.user.uid).collection('statements').orderBy('uploadedOn', 'desc').limit(50)
I get the following error:
Uncaught Error: Invalid document reference. Document references must have an even number of segments, but FrMd6Wqch8XJm32HihF14tl6Wui2 has 1
at new FirestoreError (index.cjs.js:346)
at Function.DocumentReference.forPath (index.cjs.js:15563)
at Firestore.doc (index.cjs.js:15368)
at UploadStatementPresentation.componentWillMount (UploadStatementPage.jsx:61)
at UploadStatementPresentation.componentWillMount (createPrototypeProxy.js:44)
at callComponentWillMount (react-dom.development.js:6872)
at mountClassInstance (react-dom.development.js:6968)
at updateClassComponent (react-dom.development.js:8337)
at beginWork (react-dom.development.js:8982)
at performUnitOfWork (react-dom.development.js:11814)

Since you haven't described what exactly you're trying to query, I'll just point out that all documents must be in a collection, without exception. So, if you say this:
db.doc(this.props.user.uid)
Firestore assumes that the string you're passing to doc() contains both the collection and document id separated by a slash. But this seems to be highly unlikely in your case. You need to determine which collection the uid is in, and use that first when you build the reference to the collection you want to query. Assuming that you do have a statements subcollection in the uid document, and that some other collection contains the uid document, you'll have to specify the full path like this:
db.collection('that-other-collection').doc(this.props.user.uid).collection('statements')
Of course, only you know the actual structure of your data.

If you want to get a collection of documents with querying, you don’t have to specify a document id. Below code should work in this case.
const query = db.collection('statements').orderBy('uploadedOn', 'desc').limit(50)
Or if you want to get the document, you can pass the document id to doc() method. In that case, the code should be.
const query = db.collection('statements').doc(this.props.user.uid)
For more details about querying firestorm data: https://firebase.google.com/docs/firestore/query-data/get-data?authuser=0

For others having this issue, make sure that no document reference has an empty string.
I had this issue when using a get method with uid input as below and forgot to check if uid is empty
private fun getFullRef(uid: String): CollectionReference {
return ref.document(uid).collection(FireContact.SUB_PATH)
}

Related

How do I delete a string object element stored in Redis?

I am trying to delete an entire object stored in Redis using LREM, but I don't think I am doing it right, below is the code I tried:
GraphQL mutation:
deleteImage: async(_,args) => {
let data = await client.lrem("postedImagesList",0,JSON.stringify(args.id));
return data
}
postedImagesList is a redis collection of all the object elements stringified:
1) "{\"id\":\"aadc8456-a5c9-46b9-a58c-670446d95c70\",\"url\":\"chas\",\"description\":\"asd\",\"posterName\":\"asda\",\"binned\":false,\"userPosted\":true}"
2) "{\"id\":\"a24d6d1b-224f-400d-8b84-dac83d8eaf92\",\"url\":\"ihir\",\"description\":\"helped\",\"posterName\":\"bhi\",\"binned\":false,\"userPosted\":true}"
I am given the id as an argument and I have to delete the entire object, how can I do so? I am adding the elements using lpushasync.
Please see the LREM docs.
LREM key count element
The element argument has to have an exact match, so you can't match by ID.
You might want to consider using the RedisJSON using the JSON.DEL you should be easily achieve what you're looking for.

How to generate random ID instead of auto increment in Mongoose

I am creating an app where customers can scan codes, and when scanned, it opens a website which basically redeems that code. The problem is that all these codes have an auto-incremented ID, so the customer could just redeem all possible codes just by increasing the ID number in the url.. Is there a way to generate random uuid's in mongoose instead of the default auto incremented ObjectID?
You can achieve what you are looking for by the below command:
var mongoose = require('mongoose');
var id = mongoose.Types.ObjectId('4edd40c86762e0fb12000003');
where 4edd40c86762e0fb12000003 is the custom ObjectId you desire for.
To generate a completely random non-incrementing string, use the below code.
let randomString = _.times(16, () = (Math.random()*0xF<<0).toString(24)).join('');
var id = mongoose.Types.ObjectId(randomString);
Make sure that you are Inserting/Updating is a valid ObjectId on length 24 and a duplicate of the same ObjectId doesn't exist in another document in the same collection.
To generate a random ObjectId, use the below code.
var mongoose = require('mongoose');
var id = mongoose.Types.ObjectId();
Note: A random ObjectId will be created if you don't pass any value to the parameter
Furthermore, you can insert any custom _id key inside MongoDB of any recognized MongoDB types, as long as its' unique in that collection, it will work.
Example:
db.col.insertMany([{"_id": 1}, {"_id": 2}])
db.col.insertMany([{"_id": "Product1"}, {"_id": "Product2"}])
will work just fine.
Instead of replacing the entire unique ObjectId with a random number, could you append a random number when printing out the code?
For example, parseInt(Math.floor(Math.random()*65536),16) will give you a random 4-character code. Store that as a validator when writing the document to the database, and append it to the ObjectId when generating the scannable token.
When the user scans the code, you can use the first 24 characters to look up the document, then verify that the last 4 characters match the validator. No external libraries required.
If you want to get even fancier, append a check digit or checksum on the code (such as is done with credit card numbers) so that the client side can sometimes determine that a code is invalid without even consulting the database.

how We can count cloud Firestore document of collection, based on document field condition?

I want to count the document of collection based on fields. I found one reference but giving me error
Property 'select' does not exist on type 'CollectionReference.
Below is my firestore service class code. which I applied to fetch the count.
firestore().collection(collectionName).select(documentFieldName).get().then(
(snapshot) => console.log(snapshot.docs.length));
Can any one please suggest there is other way to do ?
Now tried with this pic of code
const a = await firestore().collection(collectionName).where('createdBy',
CONDITIONS.EQUALS, reportType).get().then(a => (a.size));
It giving me as proper response number but added some string text "Invalid status code" I am not sure why added this string
Invalid status code: 19

OrderBy and StartAt with two different fields firestore

In my app, I have comments that have a field value of threadCommentCount. I want to order the comments using orderBy threadCommentCount descending and then have pagination continue this using startAfter(lastThreadCommentCount). The problem is when threadCommentCount is 0, which is a lot of them, it will return and the same data every time since it starts at 0 everytime. Here is the query:
popularCommentsQuery = db
.collection('comments')
.where('postId', '==', postId)
.orderBy('threadCommentCount', 'desc')
.startAfter(startAfter)
.limit(15)
.get()
This will return the same comments everytime once threadComment count is 0. I'm unable to send the last document snapshot because im using cloud functions and I dont want to send the documentSnapshot in a get query parameter. I don;t really care how the comments are ordered after threadCommentCount is 0, I just need to not get any duplicates. Any help is great!
All Firestore queries have an implicit orderBy("__name__", direction) to resolve any ties between documents that have the same values for the other named orderBy fields. This makes the final sort order stable. But it also enables you to pass another argument to startAfter to provide the document ID of the anchor document that you wish to use for the purpose of pagination.
.startAfter(lastThreadCommentCount, lastDocumentId)
Between these two values, you should be able to uniquely identify the document in the result set to start the next page.
so, I was trying OrderBy and StartAfter with two different fields(time,key) in firestore to establish pagination in flastList.
Key point is that we can pass document snapshot to define the query cursor [reference]
Here is how I managed to do it.
step 1: get the document Id(which is auto generated by firebase) with where() [reference]
const docRef = firestore().collection('shots').where('key','==','custom_key')
const fbDocIdGeneratedByFirebase= await docRef.get().docs[0].id;
step 2: get document snapshot with firebase generated document Id (which we got in the 1st step)
const docRef2= firestore().collection('shots').doc(fbDocIdGeneratedByFirebase)
const snapshot = await docRef2.get();
step 3: pass the snapshot got in step 2 to startAfter() so that the cursor will point there [reference]
let additionalQuery = firestore().collection('shots')
.orderBy("time", "desc")
.startAfter(snapshot)
.limit(this.state.limit)
let documentSnapshots = await additionalQuery.get(); // you know what to do next
...
Can you Improve the solution??

which is best for performance while referring using _id? While retrieving using _id, i am getting error INVALID OBJECT ID

How should i refer a collection in another collection , a unique username or default _id (object id) or a normal id that increments when a new record is inserted . I read that object ids increase performance in mongoose , but i am unable to retrieve records using _ids as its giving error INVALID OBJECT ID . i am not getting error when retrieving using other keys like username . But as _id increases performance i am trying to use that .
Model.find({_id : "idstring"})
I tried these 2 ways while defining schema ,
1) no definition for _id , as it will be created automatically
2) i defined _id like this : _id : { type : Schema.ObjectId }
In both ways, i am getting error "invalid object id" when retrieving records
thanks
You need to create an ObjectID from the string
var ObjectId = require('mongoose').Types.ObjectId;
var myObjectId = ObjectId.fromString('myhexstring');
both 1) and 2) do the same thing. its better to choose 1) and let mongoose do it for you.
i dunno about performance necessarily. the _id field just gets uniquely indexed by mongodb for you so the perf gain in queries would be due to that. you can always index whatever other fields you want if your query is slow. its easier to use _id for sure.
the INVALID OBJECT ID error is due to something being passed that cannot be cast to an ObjectId by mongoose. you can pass a hex string or an instance of mongoose.Types.ObjectId. the hex string should be 24 chars in length. double check this value.
also, explicitly casting the string to an ObjectId is done for you so there is no need to do it manually.

Resources