Find document by value without its reference - javascript

This is a database structure for my image uploading app. The first collection group is ID of the user, its childs are images, with IDs as titles.
I am trying to create a get route for example: domain.com/i/IMAGE_ID, then get that ID and provide image across the page.
Is it possible to find needed document without having the title of its parent?

Is it possible to find needed document without having the title of its parent?
Yes it is possible using a query which is related to a property. Let's assume your know the file name, then please use the following lines of code:
var uidRef = firebase.database().ref("images").ref(uid);
var query = uidRef.orderByChild("fileName").equalTo("Colour7.jpg")
In which the uid is the id of the authenticated user. The result of the query will be the second item in your images node.
Edit:
If you only have the image ID, please use the following lines of code:
var uidRef = firebase.database().ref("images").ref(uid);
var query = uidRef.orderByChild("ID").equalTo("2sj2yAJN3MC24GwjLtDkt")

Related

firestore snapshot of certain documents

Any suggestions on how to get a snapshot to only return certain
documents in a collection?
db.collection('locations-data').get().then(snapshot => {
setupLocations(snapshot.docs);
The JS setupLocations function loops through and adds data to an ul/li on the UI.It Works but it loads every document and I only want a specific document based on a users access listed in a user collection.
In my "locations-data" collection I have documents named by location (e.g. ca1001, ca1002, etc.)
And a user collection > userID > locations array to set which locations a user can view.
As mentioned above, The Setup works great on the front-end but loads all documents and I only want certain users to get certain locations (documents) to show in the UI.
I get the locations array from the users collection into a var, and have tried using map and other things on the code side, also tried a few things via security rules, etc. Just not having much luck.
Here's the code on the UI side that loads the display for the user.
// show locations
const setupLocations = (data) => {
if (data.length) {
let html = '';
data.forEach((doc) => {
const location = doc.data();
const li = `
<li>
<div class="collapsible-header grey lighten-4">
${location.shortName}, Total Income: ${location.todayIncome}
</div>
<div class="collapsible-body white">${location.totalIncome}</div>
</li>
`;
html += li;
});
locationList.innerHTML = html;
} else {
locationList.innerHTML = '<h5 class="center-align">Login to view data</h5>';
}
};
I ended up using "array-contains" and just added a users field to each document I want to include. .where('_users', 'array-contains', user.email). Will just have to create a simple admin to manage users this way to avoid having to add all users to each document manually. Thanks all for suggestions.
Any suggestions on how to get a snapshot to only return certain documents in a collection?
Since your first option is to get all document based on the users location you can use what #pepe said, the where in query filter to get a specific or certain documents inside your collection. The other option is store all the data of location from user collection to a array variable then display it directly to your UI. With that you don't need to query for location-data collection because you already got all the specific location data based on the user's data.

Appmaker: How can I get the ID of an item i just created, on client side?

So my latest problem is the following:
I store an id(a foreign key) in a custom property. I want to set the Foreign Key field of an item I just created, to the stored custom property.
I am trying to achieve this in a server script, which looks like this:
function setFKforCustomer(customerID, companyID)
{
var query = app.models.Customer.newQuery();
query.filters.Id._equals(customerID);
var records = query.run();
records[0].Company_fk=companyID;
}
I want to call this function from a client side script, which has to know the customer's ID, the id of the item I just created. I am not entirely sure I am approaching the problem from the right angle, so I am open to other ideas.
Thank you in advance (Markus)!
The question of how to manage relationships in App Maker is probably one of the most asked questions. The official documentation for your specific use case is located here https://developers.google.com/appmaker/models/relations#server_script. The answer would be as follows:
function setFKforCustomer(customerID, companyID)
{
var customerRecord = app.models.Customer.getRecord(customerID);
var companyRecord = app.models.Company.getRecord(companyID);
customerRecord.YourCompanyRelationName = companyRecord; //the field in this case is not Company_fk but whatever the name is of the relation you set up in AM
app.saveRecords([customerRecord]);
}

How do you get specific firebase data without knowing the unique id?

I have some data in my firebase database that I want to retrieve. I did one big push so that all instances would have a unique id. I know want to retrieve this data
I know I can do this:
var gymData = firebase.database().ref('gymData/previousWorkouts')
but when I get returned data like this:
how the hell am I suppose to access that id without knowing it?
for example a user of my app is going to search for an exercise and update it. they search by name, how do I find that id and look inside there? I don't get it :/
firebase.database().ref('gymData/exrcises').orderByChild('name').equal("barbell bench press").once('value', function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var childKey = childSnapshot.key;//this is id
});
});

How to create a sharable url containing dynamic html (javascript)

What is the best practice to create unique shareable urls for some text lists users create?
It's a single page website with a content div where users create text lists. Once they click share, how can I store those values inside a shareable url so that another user going to that address loads the same list?
I'm using html, js, jquery, php.
EDIT: as suggested below i'm already saving the lists on a database (firebase), and each have an unique ID, so I'd need to understand how I can create urls with a list id in it, and how to read the url back.
EDIT 2: so this is the code i'm using right now, combining answers from marzelin and the Alchemist Shahed in my other question about my database structure (Firebase how to find child knowing its id but not its parent's id (js)):
//js inside window load function:
const keyOfDynamicHtmlItemRef = new URL(window.location).searchParams.get("share")
if (keyOfDynamicHtmlItemRef) {
var dynamicHtmlListRef = firebase.database().ref('users');
// var dynamicHtmlItemRef = dynamicHtmlListRef.child(keyOfDynamicHtmlItemRef);
// console.log(keyOfDynamicHtmlItemRef);
// dynamicHtmlItemRef.once("value").then(dynamicHtmlSnap => {
// texta.innerHTML = dynamicHtmlSnap.val();
// });
dynamicHtmlListRef.once('value').then((snapshot)=>{
snapshot.forEach(function(data) {
if (data.key == keyOfDynamicHtmlItemRef) {
myVar = data.c;
myContentDiv.innerHTML = myVar;
}
});
});
}
and i'm simply trying to manually write the url in the searchbar as a first step, as https://example.com/?share=<random list id i copied from db>, but it does nothing.
So the way I would to this is I would have the users share click trigger a save to database saving all the dynamically generated content into a table.
One of the table values would be a randomly generated unique identifier of some sort that I would use as a query in the url like https://www.example.org/?share=skd822475
Then when a user visits the site and that query is in the url id use the unique identifier to look up the database and publish the dynamic content back on the page.
I would also put a half life on the database entry's of say no more than 30 days so that it doesn't clog up the db.
Saving data and creating shareable link:
document.querySelector(".share").addEventListener("click" => {
var dynamicHtmlListRef = firebase.database().ref('dynamic_html');
var dynamicHtmlItemRef = dynamicHtmlListRef.push();
dynamicHtmlItemRef.set(userCreatedDynamicHtml);
var keyOfDynamicHtmlItem = dynamicHtmlItemRef.key;
var linkToDynamicHtmlItem = `${window.location}?share=${keyofDynamicHtmlItem}`;
alert(`link: ${linkToDynamicHtmlItem}`)
})
Showing the dynamic HTML based on query parameters:
const keyOfDynamicHtmlItemRef = new URL(window.location).searchParams.get("share")
if (keyOfDynamicHtmlItemRef) {
var dynamicHtmlListRef = firebase.database().ref('dynamic_html');
var dynamicHtmlItemRef = dynamicHtmlListRef.child(keyOfDynamicHtmlItemRef);
keyOfDynamicHtmlItemRef.once("value").then(dynamicHtmlSnap => {
document.querySelector(".dynamic-html-mountpoint").innerHTML = dynamicHtmlSnap.val();
});
}
Let's start with the first question "How to create urls with a list id in it?"
The thing is that to answer this one we need to answer the second question first witch is
"How to read the url back?"
Consider that you have a php page named "draft". when a user visit https://www.example.com/draft?listId=an_id you will get listId using php like so $_GET("listId") and use that value to retrieve the list data and display the page content.
Now coming back to the first question, if the user share the draft like in social media (ex: facebook) then there is no problem because he will share a link and all his followers and any other user can access it easily. but if the user just save the draft then you will have to change the page url dynamically like this window.history.pushState(null, null, '/draft?listId=your_newly_created_id'); and so the user will copy the url and do whatever he wnt with it (sharing it in stackoverflow maybe example using jsfiddle http://jsfiddle.net/F2es9/ (you can change the url to look like this using 'htaccess' file)) at the end I would like to tell you that we don't "create" urls.
Edit
without using php code (or any other server side code). the difference will be in retrieving the data.
instead of using $_GET("listId") you will use new URL(window.location).searchParams.get("listId") to get the list id in javascript then using this value you can retrieve data from firebase and display your content

Firebase get all values of specific key

I have a users table on Firebase and each user has an email prop.
Structure looks like:
Users -> User UID (looks like n8haBbjgablobA2ranfuabu3aaaga2af) -> User Obj which includes email prop.
I'd like to get an array of all the users' emails (~1m).
How can I most efficiently do this?
Ps.:
I tried:
usersRef.startAt(0).endAt(20).once("value", function(snapshot) {
console.log('FIRST 20');
console.log(snapshot.val()); // null
});
But that fails.
Probably the most efficient approach in terms of data reads would be to denormalize your data. You could store the email addresses both in the individual user nodes and in an emailAddresses node. Then you could just query the emailAddresses node directly for your list of emails.
Still ~1m email address nodes would probably be too much all at once. I'd probably grab it in chunks... I'm guessing.
Update
"Grabbing in chunks" is essentially pagination. I would try to use something off the shelf before trying to roll my own pagination solution.
Pagination libraries to check out:
Firebase Utils Pagination: This is developed by Firebase, but they say it is experimental and not ready for production use. But, it's probably still worth messing around with.
firebase-paginator: this is developed by a community member and it seems pretty solid.
If you want to roll your own pagination, check out:
#kato's response in this StackOverflow answer He makes an interesting point about the potential problem with paginating a real time data set, but then provides some good starter code
Here's a good blog entry that talks about the code that I think is a part of the firebase-paginator library I linked to above
Everybody in their answers said that it was an easy thing, yet had no working solutions. Here's what I came up with:
usersRef.orderByChild('uid').limitToFirst(100).once('value', function (snapshot) {
var users = snapshot.val()
var uids = Object.keys(users);
var lastUid = uids[uids.length - 1];
// could be another property than uid, for example email, or username. Ps.: Consider that the last ID from the previous chunk will be duplicated.
usersRef.orderByChild('uid').startAt(lastUid).limitToFirst(100).once('value', function (snapshot) {
var users = snapshot.val()
var uids = Object.keys(users);
console.log(uids);
var lastUid = uids[uids.length - 1];
// re-run function until done
})
})
Since this is a one-time deal, an option is to simply iterate over each node in the parent 'data' node capturing the child data, stripping out the email address and dumping that to a file.
the event you want is
child_added: retrieve lists of items or listen for additions to a list
of items. This event is triggered once for each existing child and
then again every time a new child is added to the specified path. The
listener is passed a snapshot containing the new child's data.
and the code to iterate all of the child nodes in the data node is
var dataRef = firebase.database().ref('myRootRef/data');
datRef.on('child_added', function(data) {
//data.val() will contain the child data, such as the email address
//append it to a text file here (for example), save to disk etc.
});
The key here is that this event is triggered once for each child, similar to iterating over all of the indexes in an array.
This will retrieve each child and present it to your app, one child at a time, iterating over all the children within the node.
It's going to take a while with that many nodes to chew through.

Categories

Resources