I'm working with Angularjs and Firebase. Right now I'm new at firebase for this I'm struggling to find solutions for my issues.
Imagine I'm sorting users like this
users:{
facebook:123456789:{
blog: [{
// List of blogs
}],
following: [{
// List of users auth.ids
}]
},
facebook:123456780:{
blog: [{
// List of blogs
}],
following: [{
// List of users auth.ids
}]
}
}
And getting logged in user blog object and iterating and pushing it to the array like this
var blogRef = new Firebase(FirebaseUrl + "/users/" + authData.uid + "/blog");
var userBlog = $firebaseArray(blogRef);
var userBlogDatas = []
blogRef.limitToLast(10).on("child_added", function(snapshot) {
var snap = snapshot.val();
userBlogDatas.push(snap);
});
So far everything working fine.
But how can i get latest blogposts from feeds from following users. Right now I have some idea which represents getting user blog datas and pushing them into array. I'm not sure is it right way or not...
I also read https://github.com/firebase/firefeed/blob/master/www/js/firefeed.js code but I could not get any information for myself.
Any ideas will be really helpfull.
Thank you
There's a couple of ways to do this if I am understanding the question correctly.
One way is that instead of storing the user_id, store the user id as a key and the blog id as the value like
users
facebook:123456789
blog
// List of blogs
following
user_id_0: blog_id_x
user_id_1: blog_id_y
Then you can add an observer to each blog in the following node. You can get the path from the key/value pair. In this case Facebook:123456789 is following:
/users/user_id_0/blog/blog_id_x
/users/user_id_1/blog/blog_id_y
Another option would be to create a child node within the following node that contains two values: the user_id and blog_id.
users
facebook:123456789
blog
// List of blogs
following
follow_id_0
userid: user_id_0
blog: blog_id_0
follow_id_1
userid: user_id_0
blog: blog_id_1
In this case, facebook:123456789 is following user_id_0's blog 0 and blog 1
Note: user_id_0 and user_id_1 are actually Facebook:abcdefg users id's
Related
I am using Firebase to store information for a workout application.
I user adds a workout name and then I push it to the database. I can continue pushing these but my issue is that it does not seem to be pushing as an array just an object. See the screen shots below...
As you can see in the console log picture the workouts property is an object not an array like I expect.
The code I'm using to push it:
let newWorkout = {
title: 'title',
exercises: [{
name: 'pulldownsnsn',
sets: 4
}]}
let ref = firebase.database().ref("/userProfile/"+this.userId);
ref.child("workouts").push(newWorkout);
The Firebase Database stores lists of data in a different format, to cater for the multi-user and offline aspects of modern web. The -K... are called push IDs and are the expected behavior when you call push() on a database reference.
See this blog post on how Firebase handles arrays, this blog post on the format of those keys, and the Firebase documentation on adding data to lists.
Arrays are handy, but they are a distributed database nightmare for one simple reason: index element identification is not reliable when elements get pushed or deleted. Firebase database instead uses keys for element identification:
// javascript object
['hello', 'world']
// database object
{ -PKQdFz22Yu: 'hello', -VxzzHd1Umr: 'world' }
It gets tricky when using push(), because it does not actually behaves like a normal push, but rather as a key generation followed by object modification.
Example usage
firebase.database().ref('/uri/to/list').push(
newElement,
err => console.log(err ? 'error while pushing' : 'successful push')
)
Heres an example from firebase documentation:
const admin = require('firebase-admin');
// ...
const washingtonRef = db.collection('cities').doc('DC');
// Atomically add a new region to the "regions" array field.
const unionRes = await washingtonRef.update({
regions: admin.firestore.FieldValue.arrayUnion('greater_virginia')
});
// Atomically remove a region from the "regions" array field.
const removeRes = await washingtonRef.update({
regions: admin.firestore.FieldValue.arrayRemove('east_coast')
});
More info on this firebase documentation.
Sorry if this is a basic question, I'm relatively new to javascript and Meteor.
I'm trying to create a recommended page that recommends sites that you have upvoted. It takes the tags that are on the post, and puts them into the user profile under 'tags' as an array.
var websiteTags = Websites.findOne(website_id, {fields: {tag: 1} });
var getTags = websiteTags.tag;
Meteor.users.update(this_user, {$addToSet: {"profile.tags": getTags}});
Then under the templates helper, I'm trying to return a list of websites that have the tags equal to what is in the users profiles.
Template.user_recommended_list.helpers({
websites:function(){
var usersTags = Meteor.user().profile.tags;
return Websites.find({tag: usersTags});
}
});
If I add an index number like: Meteor.user().profile.tags[0], it will work, but I need to query multiple user tags against the website tag list.
I've tried looping through the users tags then return each value to the page, but it wouldn't work. What's the best way to do it?
Thanks in advance
Just use the $in operator in your mongo query:
return Websites.find({tag: {$in: usersTags}});
I have removed autopublish from my Meteor app. Now I'm publishing my collections manually. I have some related collections. I want to increase performance as much as possible.
If I'm, for instance, looking at a post and want to see all the comments related to this post, I have to query the database with both post: Posts.findOne(postId) AND comments: Comments.find({postId: postId}). I am querying the two collections in the data field with iron-router so they are present in my template but I'm also subscribing the publications in waitOn. Now I have found https://github.com/englue/meteor-publish-composite which lets me publish multiple collections at the same time. But I don't quite understand it. If I'm using Meteor.publishComposite('postAndComments', ...) in server/publish.js, subscribing postAndComments in waitOn, and setting both post and comments in data as I normally do, will I then have saved a demand on the database? To me it looks like I still query the database the same number of times. But is the queries done when publishing the only queries made while the queries done i data is only a way to retrieve what has already been queried from the database?
Besides, in example 1, it is shown how to publish top posts with the belonging comments and post/comment authors, but in the template, only the posts are outputted. How can I also output the comments and authors? Have I misunderstood the potentials of publishComments? I understand it as a kind of a join.
I used publishComposite successfully. In my example below I'm subscribing to Units matching to filter as well as Properties those units belong to.
Meteor.publishComposite('unitsWithProperties', function (filter) {
var filter = filter || {};
console.log(filter);
return {
find: function () {
var units;
units = Units.find(filter);
return units;
},
children: [
{
collectionName: 'properties',
find: function (unit) {
return Properties.find({ _id: unit.propertyId });
}
}
]
};
});
In your case I believe you can:
subscribe to Posts matching TopPosts criteria
subscribe to Comments and Authors of those posts in children: array of cursors
.
Hope this helps.
Alex
I am working to solve a problem not dissimilar to the discussion present at the following blog post. This is wishing to publish two related data sets in Meteor, with a 'reactive join' on the server side.
https://www.discovermeteor.com/blog/reactive-joins-in-meteor/
Unfortunately for me, however, the related collection I wish to join to, will not be joined using the "_id" field, but using another field. Normally in mongo and meteor I would create a 'filter' block where I could specify this query. However, as far as I can tell in the PWR package, there is an implicit assumption to join on '_id'.
If you review the example given on the 'publish-with-relations' github page (see below) you can see that both posts and comments are being joined to the Meteor.users '_id' field. But what if we needed to join to the Meteor.users 'address' field ?
https://github.com/svasva/meteor-publish-with-relations
In the short term I have specified my query 'upside down' (as luckily I m able to use the _id field when doing a reverse join), but I suspect this will result in an inefficient query as the datasets grow, so would rather be able to do a join in the direction planned.
The two collections we are joining can be thought of as like a conversation topic/header record, and a conversation message collection (i.e. one entry in the collection for each message in the conversation).
The conversation topic in my solution is using the _id field to join, the conversation messages have a "conversationKey" field to join with.
The following call works, but this is querying from the messages to the conversation, instead of vice versa, which would be more natural.
Meteor.publishWithRelations({
handle: this,
collection: conversationMessages,
filter: { "conversationKey" : requestedKey },
options : {sort: {msgTime: -1}},
mappings: [{
//reverse: true,
key: 'conversationKey',
collection: conversationTopics,
filter: { startTime: { $gt : (new Date().getTime() - aLongTimeAgo ) } },
options: {
sort: { createdAt: -1 }
},
}]
});
Can you do a join without an _id?
No, not with PWR. Joining with a foreign key which is the id in another table/collection is nearly always how relational data is queried. PWR is making that assumption to reduce the complexity of an already tricky implementation.
How can this publish be improved?
You don't actually need a reactive join here because one query does not depend on the result of another. It would if each conversation topic held an array of conversation message ids. Because both collections can be queried independently, you can return an array of cursors instead:
Meteor.publish('conversations', function(requestedKey) {
check(requestedKey, String);
var aLongTimeAgo = 864000000;
var filter = {startTime: {$gt: new Date().getTime() - aLongTimeAgo}};
return [
conversationMessages.find({conversationKey: requestedKey}),
conversationTopics.find(requestedKey, {filter: filter})
];
});
Notes
Sorting in your publish function isn't useful unless you are using a limit.
Be sure to use a forked version of PWR like this one which includes Tom's memory leak fix.
Instead of conversationKey I would call it conversationTopicId to be more clear.
I think this could be now much easier solved with the reactive-publish package (I am one of authors). You can make any query now inside an autorun and then use the results of that to publish the query you want to push to the client. I would write you an example code, but I do not really understand what exactly do you need. For example, you mention you would like to limit topics, but you do not explain why would they be limited if you are providing requestedKey which is an ID of a document anyway? So only one result is available?
I have a blogs collection that contains title, body and agrregate rating that the users have given to them. Another collection 'Ratings' whose schema has reference to the blog, user who rated(if at all he rates them) it in the form of their ObjectIds and the rating they have given ie., +1 or -1.
When a particular user browses through blogs in the 'latest first' order (say 40 of them per page. Call them an array of blogs[0] to blogs[39]) I have to retrieve the rating documents related to this particular user and those 40 blogs if at all the user rated them and notify him of what ratings he has given those blogs.
I tried to extract all rating documents of a particular user in which blog reference objectIds lie between blogs[0]._id and blogs[39]._id which returns empty list in my case. May be objectIds cant be compared using $lt and $gt queries. In that case how should I go about it? Should I redesign my schemas to fit to this scenario?
I am using mongoosejs driver for this case. Here are the relevant parts of the code which differ a bit in execution but youu get the idea.
Schemas:
Client= new mongoose.Schema({
ip:String
})
Rates = new mongoose.Schema({
client:ObjectId,
newsid:ObjectId,
rate:Number
})
News = new mongoose.Schema({
title: String,
body: String,
likes:{type:Number,default:0},
dislikes:{type:Number,default:0},
created:Date,
// tag:String,
client:ObjectId,
tag:String,
ff:{type:Number,default:20}
});
models:
var newsm=mongoose.model('News', News);
var clientm=mongoose.model('Client', Client);
var ratesm=mongoose.model('Rates', Rates);
Logic:
newsm.find({tag:tag[req.params.tag_id]},[],{ sort:{created:-1},limit: buffer+1 },function(err,news){
ratesm.find({client:client._id,newsid:{$lte:news[0]._id,$gte:news.slice(-1)[0]._id}},function(err,ratings){
})
})
Edit:
While implementing the below said schema, I had to do this query in mongoose.js
> db.blogposts.findOne()
{ title : "My First Post", author: "Jane",
comments : [{ by: "Abe", text: "First" },
{ by : "Ada", text : "Good post" } ]
}
> db.blogposts.find( { "comments.by" : "Ada" } )
How do I do this query in mongoose?
A good practice with MongoDB (and other non-relational data stores) is to model your data so it is easy to use/query in your application. In your case, you might consider denormalizing the structure a bit and store the rating right in the blog collection, so a blog might look something like this:
{
title: "My New Post",
body: "Here's my new post. It is great. ...",
likes: 20,
dislikes: 5,
...
rates: [
{ client_id: (id of client), rate: 5 },
{ client_id: (id of another client), rate: 3 },
{ client_id: (id of a third client), rate: 10 }
]
}
The idea being that the objects in the rates array contains all the data you'll need to display the blog entry, complete with ratings, right in the single document. If you also need to query the rates in another way (e.g. find all the ratings made by user X), and the site is read-heavy, you may consider also storing the data in a Rates collection as you're doing now. Sure, the data is in two places, and it's harder to update, but it may be an overall win after you analyze your app and how it accesses your data.
Note that you can apply indexes deep into a document's structure, so for example you can index News.rates.client_id, and then you can quickly find any documents in the News collection that a particular user has rated.