mongoose query with different input - javascript

I want to check in a db if 'test' exists in a document, in a specific field. If exists, I want to increment it by 1, to look like this 'test-1', and then check again in the db, and repeat until it's not found, than save it there.
I don't have a problem with the increment part, just with the mongoose/mongodb part where I need to re-query with the new value. Is there any way that can be done in the same query, multiple times?
Edited: I want to create a new field based on the name, but I want this field to be unique, because I want to use it as an id.
So, for instance, if I have something like name: 'John Smith' I want to create a new field in my document like this: uniqueId: john-smith, for the same document. The problem is, if another John Smith is inserted in my collection, I want to check if the uniqueId john-smith is available, if not I want to append a -1 to it, so it will look like this john-smith-1, and so on, until a john-smith-(number) is not found, then I will know the id is unique and save it to the document.
One idea would be to use a Model.find() inside of a recursive function with the uniqueId, and repeat until a document is not found. But I was wondering if there might be another way, maybe something less complicated?
mongodb v4.2.3

Related

Firestore data model is inconsistent

I'm trying to save some data in firestore, the data consists of events, each event has a date and each some attendees.
What I'm trying to do now is model it like this events/${eventDate}/${userEmail} and then I would set this with the user's data. However when I try to set this data I get an error saying that the segment number should be even.
When I added another segment in the path (which I didn't want to do):
events/${eventDate}/attendees/${userEmail} I was able to set the data but I wasn't able to retrieve it (trying to retrieve all attendees of a given event date.
// insertion - this worked after some tweaking
this.db.collection('pickups').doc(pickupDate).set({ [email]: userData})
// deletion (this doesn't work - expects even number of segments)
this.db.collection('pickups').doc(`${pickupDate}/${email}`).delete()
// retrieval (works)
this.db.collection('pickups').doc(pickupDate).valueChanges()
Current delete:
this.db.collection('pickups').doc(pickupDate).update({
[email]: firestore.FieldValue.delete()
})
What am I missing here? Isn't this supposed to be like regular JSON?
The path you're currently trying events/${eventDate}/${userEmail} is interpreted as a collection (events) then a document (eventDate) then another document (userEmail).
What you actually have is a collection, document within that collection, field within that document.
It looks like you're adding the email correctly (I would remove the brackets around the word email though), but trying to delete incorrectly. You delete fields like this:
var removeCapital = cityRef.update({
capital: firebase.firestore.FieldValue.delete()
});
You can see the documentation here: https://firebase.google.com/docs/firestore/manage-data/delete-data#fields
The delete may look like this:
this.db.collection('pickups').doc(pickupDate).update({
email: firebase.firestore.FieldValue.delete()
})
It sounds like what you're trying to do is delete a field out of a document. However, this code you have:
this.db.collection('pickups').doc(`${pickupDate}/${email}`).delete()
is trying to build a reference to a collection, then delete it. It's not correct to use collection() and doc() to reference fields in a document. They are just used to build references to documents and collections.
If you want to delete a field in a document, first build a reference to the document that contains the field:
const ref = this.db.collection('pickups').doc(pickupDate)
Then update the document to indicate that you want the field removed:
ref.update({ [email]: firebase.firestore.FieldValue.delete() }}
The way you reference delete() out of FieldValue is going to change based on how you have the SDK imported into your code.
See the documentation on deleting fields for more information.

Set value of field in Firestore document only if the field hasn't already been set

I have a collection whose documents look something like this:
count: number
first: timestamp
last: timestamp
The first value should (almost) never change after the document's creation.
In a batch write operation, I am trying to update documents in this collection, or create those documents that do not yet exist. Something like
batch.setData([
"count": FieldValue.increment(someInteger),
"first": someTimestamp,
"last": someTimestamp
], forDocument: someDocumentRef, mergeFields: ["count","last"])
My hope was that by excluding first from the mergeFields array, Firestore would set count and last by merging it into an existing document or making a new one, and set first only if it had no previous value (i.e., the document didn't exist before this operation). It is clear to me now that this is not the case, and instead first is completely ignored. Now I'm left wondering what the Firestore team intended for this situation.
I know that I could achieve this with a Transaction, but that doesn't tie in very well with my batch write. Are Transactions my only option, or is there a better way to achieve this?
I have created timestamps and other data in my documents and I handle this using separate create and update functions rather than trying to do it all at once.
The initial creation function includes the created date etc and then subsequent updates use the non-destructive update, so just omit any fields in the update payload you do not want to overwrite.
eg. to create:
batch.set(docRef, {created: someTimestamp, lastUpdate: someTimestamp})
then to update:
batch.update(docRef, {lastUpdate: someTimestamp, someOtherField: someData})
This will not overwrite the creationDate field or any other fields, but will create the someOtherField if it does not exist.
If you have a need to do a "only update existing fields" update after the document is created for the first time then currently you have to read the document first to find out if the fields exist and then create an update payload which will patch the only the desired fields. This can be done in a transaction or you can write this logic yourself, depending on your needs.

Better way to refer to entries in firebase

As far as I know, firebase assigns automatically an unique ID to every new entry in the database. However - these ids are really long and not good looking.
Whats more - I have to refer to them somehow, so currently when Im doing a get request, e.g. to get one entry Im doing something like:
/getEntry/L4Cu7UOENIivnB2bgt
And it's fine, since user doesn't see it anyways.
Hovewer, when making routes to every entry in my app, again I have to refer to specific entry by it's id. So e.g. if Im on route of specified element, e.g.:
http://myapp.com/users/L4Cu7UOENIivnB2bgt - it doesn't look very well if not ugly. If I would make my db in e.g. SQL or NoSQL, I would be able to assign an id by myself so it would increase from 1 and so on.
Q: Am I able to change these long id's somehow? It has to be fixable somehow... Thanks.
Yes you can set your own unique key. Say you have unique usernames for each user then you can do
firebase.database().ref('users/' + userName).set({
firstName: name,
email: email,
profile_picture : imageUrl
});
or you can create your own unique ids and use instead. But there is no auto incremental ids.
Using set() overwrites data at the specified location, including any child nodes.

Meteor: retrieve value from document in collection

I have a Collection named "balance". I want to get the value of one document in the collection. In order to get only the latest element in the collection I use this query:
db.balance.find().sort({date: -1}).limit(1);
There's a column called 'value' and I want to get that.
db.balance.find().sort({date: -1}).limit(1).value; however does not show the data I want. It shows nothing:
What's wrong with it?
find returns a cursor. You'll need to convert it to an array in order to actually extract the value. Try this:
db.balance.find().sort({date: -1}).limit(1).toArray()[0].value;
This is, of course, much easier inside of meteor (either in code or via meteor shell) because you can do:
Balance.findOne({}, {sort: {date: -1}}).value;

Safely using eval to use variable as an object name

As shown in this example
javascript-use-variable-as-object-name
I am using eval to use a DOM attribute to select an element from an array. Though there is no direct way for the user to change the input, I want to be as secure as possible and make sure that the variable is indeed an integer before I evaluated it.
Which of the following would be the best, most secure, way?
$(".listitem").click(function(){
var id = $(this).attr("record-id");
if(!isNaN(new Number(id))){
Storage.search.nearby.currec = rowsHolder[eval(id)];
}else{
// send email to admin, shut down
}
});
or
$(".listitem").click(function(){
var id = $(this).attr("record-id");
if(parseInt(id)){
Storage.search.nearby.currec = rowsHolder[eval(id)];
}else{
// send email to admin, shut down
}
});
More, but not required info:
Basically I am pulling down a large JSON string from online, containing an array of records. Upon building a table from the info using a for statement ( for(i in array) ), I push each row into an array called rowsHolder and give the tr an attribute of record-id="i". Then when the user clicks the row, I call the method you see above. I am using PhoneGap with JQuery Mobile.
As always, thanks for the input
-D
There is absolutely no reason to use eval here.
If your id is kind of a number, use parseFloat(id) to get it. Unnecessary as it would be converted back to a string when used as a property name, though.
If your id is an integer, use parseInt(id, 10) to get it. Unnecessary as it would be converted back to a string when used as a property name, though.
If your id is a string, just let it be a string. The property name you use it for would be one anyway.

Categories

Resources