I was trying to get some data organized under a specific Id from a realtime database
For example, this is my JSON object :
{
1: {
Name :"karan",
Bio:"hello this is Karan",
}
2: {
Name :"gandhi",
Bio:"hello this is gandhi",
}
}
I want all the data to be arranged in 1. Is there any way to do this? It would be better if the data would be arranged in a object in the following format :
var data = {
Name : "karan",
Bio : "hello this is Karan",
}
This should be in the same order given in the original object
Thank you
I think what you are looking for is Object.values().
Let's suppose your database looks like:
{
1: {
"Name" : "karan",
"Bio" : "hello this is Karan",
},
2: {
"Name" : "gandhi",
"Bio" : "hello this is gandhi",
}
}
You want to retrieve data without the keys "1" and "2". Your query will be:
// Let's call your node "foo"
firebase.database().ref("foo").once("value").then(data => {
console.log(Object.values(data.val()));
});
Try to execute the following:
var data = {
1: {
"Name" : "karan",
"Bio" : "hello this is Karan",
},
2: {
"Name" : "gandhi",
"Bio" : "hello this is gandhi",
}
}
console.log(Object.values(data));
Read more here: https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Object/values
Related
I have a problem with GiftedChat, the messages appear completely disorganized in the app and even looking for messages directly from the firebase (where it is correct), the app does not get a logical order. When sending is organized, however the problem is when you load the messages. I'm completely lost
loadMessages = async () => {
const { user } = this.props;
const matchId = this.props.navigation.getParam('matchId');
const data = (await firebase.database().ref(`matchs/${matchId}/messages`).limitToLast(300).once('value')).val();
let messages = [];
if(data){
Object.keys(data)
.forEach(messageId => {
let message = data[messageId];
if(_.get(message, 'user._id') !== user.uid) _.push(message);
messages.push(message);
});
}
this.setState(() => ({
messages,
}));
}
My JSON:
{
"-LkAMYoS3fySk46Pbpan" : {
"_id" : "f5ba3d9a-c346-4f79-b371-c5d54798567e",
"createdAt" : 1563558815857,
"text" : "First message",
"user" : {
"_id" : "BVY4MDwSaaSDI2bAGjwkZlYktsK2",
"avatar" : "https://firebasestorage.googleapis.com/v0/b/wefound-760f2.appspot.com/o/users%2FBVY4MDwSaaSDI2bAGjwkZlYktsK2%2Fphotos%2Fk1xuqv26wdrjxoxmp8m.jpg?alt=media&token=7c16a0e4-2cb8-45a5-83a4-635d49c71180",
"name" : "Rafael"
}
},
"-LkAMZiITDxHE1WfCBGC" : {
"_id" : "c2755b48-136d-4a68-b283-377ebac7df8e",
"createdAt" : 1563558819564,
"text" : "Second message",
"user" : {
"_id" : "BVY4MDwSaaSDI2bAGjwkZlYktsK2",
"avatar" : "https://firebasestorage.googleapis.com/v0/b/wefound-760f2.appspot.com/o/users%2FBVY4MDwSaaSDI2bAGjwkZlYktsK2%2Fphotos%2Fk1xuqv26wdrjxoxmp8m.jpg?alt=media&token=7c16a0e4-2cb8-45a5-83a4-635d49c71180",
"name" : "Rafael"
}
},
"-LkAM_l4o_w_QeCsYRc8" : {
"_id" : "65772152-afd9-4353-b752-ac65978a536d",
"createdAt" : 1563558823838,
"text" : "Third message",
"user" : {
"_id" : "BVY4MDwSaaSDI2bAGjwkZlYktsK2",
"avatar" : "https://firebasestorage.googleapis.com/v0/b/wefound-760f2.appspot.com/o/users%2FBVY4MDwSaaSDI2bAGjwkZlYktsK2%2Fphotos%2Fk1xuqv26wdrjxoxmp8m.jpg?alt=media&token=7c16a0e4-2cb8-45a5-83a4-635d49c71180",
"name" : "Rafael"
}
},
"-LkAMcSSTOP7L1CwyiU4" : {
"_id" : "e69f3a72-0f4e-4c06-a763-518ef1984aa0",
"createdAt" : 1563558834859,
"text" : "Fourth message",
"user" : {
"_id" : "BVY4MDwSaaSDI2bAGjwkZlYktsK2",
"avatar" : "https://firebasestorage.googleapis.com/v0/b/wefound-760f2.appspot.com/o/users%2FBVY4MDwSaaSDI2bAGjwkZlYktsK2%2Fphotos%2Fk1xuqv26wdrjxoxmp8m.jpg?alt=media&token=7c16a0e4-2cb8-45a5-83a4-635d49c71180",
"name" : "Rafael"
}
},
"-LkAMduvBrEnUG6POGKt" : {
"_id" : "897b2042-25dc-46ec-a5f3-5bdc1fc355dd",
"createdAt" : 1563558840853,
"text" : "Fifth message",
"user" : {
"_id" : "BVY4MDwSaaSDI2bAGjwkZlYktsK2",
"avatar" : "https://firebasestorage.googleapis.com/v0/b/wefound-760f2.appspot.com/o/users%2FBVY4MDwSaaSDI2bAGjwkZlYktsK2%2Fphotos%2Fk1xuqv26wdrjxoxmp8m.jpg?alt=media&token=7c16a0e4-2cb8-45a5-83a4-635d49c71180",
"name" : "Rafael"
}
}
}
I gave console.tron.log () in the messages and they appear disorganized exactly the same is in the app, the problem is in the component?
1 - refers to the function that loads the messages.
2 - JSON file
There are two steps to ordering the data:
Telling the Firebase Database server to return the child nodes in the correct order.
Maintaining that order in your client-side code.
As far as I can tell your code does neither of these, which means the nodes end up in whatever order your client uses for JSON properties (which are by definition unordered).
Let's first see how to retrieve the data in the correct order from Firebase:
const snapshot = (await firebase.database().ref(`matchs/${matchId}/messages`).orderByChild('createdAt').limitToLast(300).once('value'));
The above orders all child nodes by the value of their createdAt property, then returns the last 300 in order to the client.
You'll note that I don't call val() here yet. The reason for that is that snapshot.val() returns a JSON object, and properties in a JSON object have no defined order. So if you call .val() too early, you lose the ordering information that the server returned.
Next up is processing them in the client-side code to not lose that order, which depends on using DataSnapshot.forEach():
data.forEach((message) => {
messages.push(message.val());
})
Finally, I am able to solve this problem by sorting the JSON which is coming to from the server based on the date and time(CreatedAT).
If the JSON data stored in a variable called discussion then your code should be
discussion.sort(function compare(a, b) {
var dateA = new Date(a.createdAt);
var dateB = new Date(b.createdAt);
return dateB - dateA;
});
In your case, data or messages is the one which holds the JSON. Add this code once you get the code in JSON format.
Thank you.
Summary: Need a way to search the firebase database and append the matched object with a new element.
Firebase database structure is this:
{
"Message2" : {
"-KnSKLk3dhRf8MgjZAnO" : {
"var1" : "value1",
"var2" : "value2",
"endDate1" : "Click to enter",
"searchvar" : "Uhrts",
"name" : "name",
"numbervar" : "5",
"startDate1" : "Click to enter",
"varName" : "Neptune"
},
"-KnSKLvtA3X3NsoErfa-" : {
"var1" : "value2",
"var2" : "value3",
"endDate1" : "Click to enter",
"searchvar" : "qwe",
"name" : "name",
"numbervar" : "5",
"startDate1" : "Click to enter",
"varName" : "Neptune"
}
}
}
End goal is to search the string(say "Uhrts") in each element of root node(Messages2), and if string is present, append a new parameter to all childs of Messages2 which matches the Uhrts search(to say -KnSKLk3dhRf8MgjZAnO, ... etc).
This is the index.js code I am deploying in firebase:
'use strict';
const functions = require('firebase-functions');
exports.qwerty = functions.database.ref('/Messages2').onWrite(event => {
const message = event.data.val();
if (message) {
var string = new RegExp("Uhrts");
var upper;
var lower;
for (upper in message){
for (lower in message[upper]){
if (string.test(message[upper][lower])) {
message[upper].cost = "1500000";
return event.data.adminRef.update({
});
}
}
}
}
});
When I try to dump the data under -KnSKLk3dhRf8MgjZAnO into console, it has "cost" correctly updated for it, but the database itself is not updated and remains unchanged. What am I missing?
Also, I want this to happen to all child elements which have Uhrts, but the console only prints out the first match it finds. Does the 2 for loops not take care of traversing all the elements if the ref is for Messages2? How do I append to ALL the elements of the database structure instead of only one?
I am OK with changing the database structure or the code as long as the end goal described here is met.
So, I have the following firebase structure, whose keys firebase has enumerated, starting at 0. So in the following example the key are numbered 0-3:
"comments" : {
"BAcyDyQwcXX" : [
{
"text" : "Wes. WE should have lunch.",
"user" : "jdaveknox"
},
{
"text" : "#adults",
"user" : "jdaveknox"
},
{
"text" : "#jdtroy yes!",
"user" : "wesbos"
},
{
"text" : "😍 love choccolate!",
"user" : "willowtreemegs"
}
]
}
What I want to do is:
get the current record count,
create a new key by incrementing the current record count + 1
write the new details to the child() index of comments
I have the second and third stage of the process completed,
var commentData = {
text: text,
user: user
};
updates['/comments/' + childindex +'/' + newCommentKey] = commentData;
return firebase.database().ref().update(updates);
I just need to know how to get the current record count. How do I do this?
I'm attempting to filter returned data sets with Meteor's find().fetch() to contain just a single object, it doesn't appear very useful if I query for a single subdocument but instead I receive several, some not even containing any of the matched terms.
I have a simple mixed data collection that looks like this:
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e7"),
"name" : "Entertainment",
"items" : [
{
"_id" : ObjectId("57a38b5f2bd9ac8225caff06"),
"slug" : "this-is-a-long-slug",
"title" : "This is a title"
},
{
"_id" : ObjectId("57a38b835ac9e2efc0fa09c6"),
"slug" : "mc",
"title" : "Technology"
}
]
}
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e8"),
"name" : "Sitewide",
"items" : [
{
"_id" : ObjectId("57a38bc75ac9e2efc0fa09c9"),
"slug" : "example",
"name" : "Single Example"
}
]
}
I can easily query for a specific object in the nested items array with the MongoDB shell as this:
db.categories.find( { "items.slug": "mc" }, { "items.$": 1 } );
This returns good data, it contains just the single object I want to work with:
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e7"),
"items" : [
{
"_id" : ObjectId("57a38b985ac9e2efc0fa09c8")
"slug" : "mc",
"name" : "Single Example"
}
]
}
However, if a similar query within Meteor is directly attempted:
/* server/publications.js */
Meteor.publish('categories.all', function () {
return Categories.find({}, { sort: { position: 1 } });
});
/* imports/ui/page.js */
Template.page.onCreated(function () {
this.subscribe('categories.all');
});
Template.page.helpers({
items: function () {
var item = Categories.find(
{ "items.slug": "mc" },
{ "items.$": 1 } )
.fetch();
console.log('item: %o', item);
}
});
The outcome isn't ideal as it returns the entire matched block, as well as every object in the nested items array:
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e7"),
"name" : "Entertainment",
"boards" : [
{
"_id" : ObjectId("57a38b5f2bd9ac8225caff06")
"slug" : "this-is-a-long-slug",
"name" : "This is a title"
},
{
"_id" : ObjectId("57a38b835ac9e2efc0fa09c6")
"slug" : "mc",
"name" : "Technology"
}
]
}
I can then of course filter the returned cursor even further with a for loop to get just the needed object, but this seems unscalable and terribly inefficient while dealing with larger data sets.
I can't grasp why Meteor's find returns a completely different set of data than MongoDB's shell find, the only reasonable explanation is both function signatures are different.
Should I break up my nested collections into smaller collections and take a more relational database approach (i.e. store references to ObjectIDs) and query data from collection-to-collection, or is there a more powerful means available to efficiently filter large data sets into single objects that contain just the matched objects as demonstrated above?
The client side implementation of Mongo used by Meteor is called minimongo. It currently only implements a subset of available Mongo functionality. Minimongo does not currently support $ based projections. From the Field Specifiers section of the Meteor API:
Field operators such as $ and $elemMatch are not available on the client side yet.
This is one of the reasons why you're getting different results between the client and the Mongo shell. The closest you can get with your original query is the result you'll get by changing "items.$" to "items":
Categories.find(
{ "items.slug": "mc" },
{ "items": 1 }
).fetch();
This query still isn't quite right though. Minimongo expects your second find parameter to be one of the allowed option parameters outlined in the docs. To filter fields for example, you have to do something like:
Categories.find(
{ "items.slug": "mc" },
{
fields: {
"items": 1
}
}
).fetch();
On the client side (with Minimongo) you'll then need to filter the result further yourself.
There is another way of doing this though. If you run your Mongo query on the server, you won't be using Minimongo, which means projections are supported. As a quick example, try the following:
/server/main.js
const filteredCategories = Categories.find(
{ "items.slug": "mc" },
{
fields: {
"items.$": 1
}
}
).fetch();
console.log(filteredCategories);
The projection will work, and the logged results will match the results you see when using the Mongo console directly. Instead of running your Categories.find on the client side, you could instead create a Meteor Method that calls your Categories.find on the server, and returns the results back to the client.
process.env.ENVIRONMENT = dev2
Input JSON:
{
"base": {
"product1" : "dev1.awesomeproduct1.com",
"product2" : "dev1.awesomeproduct2.com"
}
}
Output JSON:
Based on the process.env.ENVIRONMENT the product urls should be updated dynamically
{
"base": {
"product1" : "dev2.awesomeproduct1.com",
"product2" : "dev2.awesomeproduct2.com"
}
}
Do I correctly understand that you want to replace the part of the domain names up to the dot with your process.env.ENVIRONMENT variable?
Then the following code should work:
for (key in myJSON.base) {
myJSON.base[key] = myJSON.base[key].replace(/^[^.]+/, process.env.ENVIRONMENT);
}
Obviously, you will need to amend it if there are other fields than product<n> in the base object, or if you need to do a more complex replacement.