Updating MongoDB - javascript

Does anyone know how I can update in MongoDB.
I want to update the totalVisits with timesvisted
// Test data
var currentUser = "John"
var currentPage = "pageName"
var timesvisited = 59
Page.find({"_id" : currentUser}, [], {},function(err, pages) {
pages = pages.map(function(ud) {
return { userDetails: ud};
});
//database structure example
{ "_id" : "John",
"pageName" : { "totalVisits" : 58,
"timeOnPage" : 2432,
"lastVisitDate" : "10/11/2011",
"clickNoOnPage" : "5"
},
"anotherPageName" : { "totalVisits" : 18,
"timeOnPage" : 5362,
"lastVisitDate" : "01/10/2011",
"clickNoOnPage" : "15"
I am trying to update the totalVisits value and have tried something like
{$set : { pages[0].userDetails[currentPage].totalVisits : timesvisted}}
However I get a "SyntaxError: Unexpected token [" message
One of the problems I am having is with the [currentPage] section as currentPage can change so I can not hard code the pageName in.
Edit ***
I have modified this line
lastVisitedSiteDate = {$set : { "pageName.totalVisits" : timesvist}};
and this works fine. However, I need the pageName not to be hard coded in, its needs to be something like currentPage so different page names can be passed into it e.g. anotherPageName.

The second parameter to Mongo's find function specifies which fields to pull back. It needs to be a document, as in {}, not an array.

Related

Include if..else... statement in JS forEach method?

While trying to update a dictionary inside the iterator I got the error "SyntaxError: expected expression, got keyword 'if'"
The ut_frequencies data looks like:
{ "_id" : "app1", "cnt" : 3422 }
{ "_id" : "app2", "cnt" : 2752 }
{ "_id" : "app3", "cnt" : 2736 }
{ "_id" : "app4", "cnt" : 2711 }
Which I suppose is a list of dictionaries. I want to check if the app is already in the data dictionary and if so, update the "utf" value, if not, then add a new item only with the "utf" attribute set.
ut_frequencies.forEach(item=>
if(item._id in data){
data[item._id]["utf"] = item.cnt;
}else{
data[item._id] = {utf: item.cnt, atf: 0, ptf: 0};
}
)
Which is the best way to solve this.
The problem is that on the right of the arrow, an expression is expected.
An if condition is not an expression, therefore you should put braces around the body of the function.
ut_frequencies.forEach(item => {
if(item._id in data){
data[item._id]["utf"] = item.cnt;
}else{
data[item._id] = {utf: item.cnt, atf: 0, ptf: 0};
}
});

Firebase filter with pagination

I'm doing an opensource Yelp with Firebase + Angular.
My database:
{
"reviews" : {
"-L0f3Bdjk9aVFtVZYteC" : {
"comment" : "my comment",
"ownerID" : "Kug2pR1z3LMcZbusqfyNPCqlyHI2",
"ownerName" : "MyName",
"rating" : 2,
"storeID" : "-L0e8Ua03XFG9k0zPmz-"
},
"-L0f7eUGqenqAPC1liYj" : {
"comment" : "me second comment",
"ownerID" : "Kug2pR1z3LMcZbusqfyNPCqlyHI2",
"ownerName" : "MyName",
"rating" : 3,
"storeID" : "-L0e8Ua03XFG9k0zPmz-"
},
},
"stores" : {
"-L0e8Ua03XFG9k0zPmz-" : {
"description" : "My good Store",
"name" : "GoodStore",
"ownerID" : "39UApyo0HIXmKPrTOi8D0nWLi6n2",
"tags" : [ "good", "health", "cheap" ],
}
},
"users" : {
"39UApyo0HIXmKPrTOi8D0nWLi6n2" : {
"name" : "First User"
},
"Kug2pR1z3LMcZbusqfyNPCqlyHI2" : {
"name" : "MyName",
"reviews" : {
"-L0f3Bdjk9aVFtVZYteC" : true,
"-L0f7eUGqenqAPC1liYj" : true
}
}
}
}
I use this code below to get all store's reviews (using AngularFire2)
getReviews(storeID: string){
return this.db.list('/reviews', ref => {
return ref.orderByChild('storeID').equalTo(storeID);
});
}
Now, I want to make a server-side review pagination, but I think I cannot do it with this database structure. Am I right? Tried:
getReviews(storeID: string){
return this.db.list('/reviews', ref => {
return ref.orderByChild('storeID').equalTo(storeID).limitToLast(10) //How to make pagination without retrive all data?
});
}
I thought that I could put all reviews inside stores, but (i) I don't want to retrieve all reviews at once when someone ask for a store and (ii) my review has a username, so I want to make it easy to change it (that why I have a denormalized table)
For the second page you need to know two things:
the store ID that you want to filter on
the key of the review you want to start at
You already have the store ID, so that's easy. As the key to start at, well use the key of the last item on the previous page, and then just request one item extra. Then finally, you'll need to use start() (and possibly endAt() for this:
return this.db.list('/reviews', ref => {
return ref.orderByChild('storeID')
.startAt(storeID, lastKeyOnPreviousPage)
.limitToLast(11)
});
Refer this and this documentation.
For the first page:
snapshot = await ref.orderByChild('storeID')
.equalTo(store_id) //store_id is the variable name.
.limitToLast(10)
.once("value")
Store the firstKey (NOT the lastKey) from the above query. (Since you are using limitToLast())
firstKey = null
snapshot.forEach(snap => {
if (!firstKey)
firstKey = snap.key
// code
})
For the next page:
snapshot = await ref.orderByChild('storeID') //storeID is the field name in the database
.startAt(store_id) //store_id is the variable name which has the desired store ID
.endAt(store_id, firstKey)
.limitToLast(10 + 1) //1 is added because you will also get value for the firstKey
.once("value")
The above query will fetch 11 list data which will contain one redundant data from the first page's query.
How it works:
startAt ( value : number | string | boolean | null , key ? : string ) : Query
The starting point is inclusive, so children with exactly the specified value will be included in the query. The optional key argument can be used to further limit the range of the query. If it is specified, then children that have exactly the specified value must also have a key name greater than or equal to the specified key.
endAt ( value : number | string | boolean | null , key ? : string ) : Query
The ending point is inclusive, so children with exactly the specified value will be included in the query. The optional key argument can be used to further limit the range of the query. If it is specified, then children that have exactly the specified value must also have a key name less than or equal to the specified key.
So the query will try to fetch:
storeID >= store_id && storeID <= store_id (lexicographically)
which will equal to
storeID == store_id

Firebase: HowTo update the value item of a record without knowing its unique id?

So, I have a firebase structure as follows:
"Posts" : {
"0" : {
"code": 12345TG4
"Likes" : 59
},
"1" : {
"code": RT560451
"Likes" : 12
}
}
Ideally what I want to do is:
var updateData = {
Likes: 74
}
Posts.child(id).update(updateData);
But I don't know the UiD in advance, but I do have the value of the 'code', which is itself a unique value.
How do I create a query which can update the value 'Likes' based on the known value of 'code' in Firebase?
As Doug commented and Rodrigo showed, you'll have to first query for the item based on its code, before you can update it:
var ref = firebase.database().ref();
ref.child("Posts").orderByChild("code").equalTo("12345TG4").once("value", function(snapshot) {
snapshot.forEach(function(child) {
child.ref.update(updateData);
});
});
Change your model
Although the above will work, you should consider why you're storing your posts under an array index, then they also have a unique ID already. It is more idiomatic in NoSQL solutions such as Firebase to store the posts under the code:
"Posts" : {
"12345TG4" : {
"Likes" : 59
},
"RT560451" : {
"Likes" : 12
}
}
Which you'd update with:
ref.child("Posts").child("12345TG4").update({ Likes: 74 });
Or even:
"PostLikes" : {
"12345TG4" : 59,
"RT560451" : 12
}
And then:
ref.child("PostLikes/12345TG4/Likes").set(74);
Try to do this.
var ref = firebase.database().ref("Posts");
ref.orderByChild("code").on("child_added", function(snapshot) {
snapshot.ref.update(updateData);
});

How to query based on multiple conditions in Firebase?

I have this following structure:
{
"users" : {
"123" : {
"activities" : {
"horse" : "horse",
"bike" : "bike"
},
"age" : 21
},
"124" : {
"activities" : {
"bike" : "bike"
},
"age" : 30
}
}
I am trying to do something similar to:
SELECT * FROM users WHERE (activities = 'horse' OR activities = 'bike') AND age >= 21
Can I please get some pointers on this? If I didn't structured the data properly, can I also get some tips there?
edit: jsfiddle
I will mark this question as a duplicate, but this code might be helpful for you to get started building your own search index:
var ref = new Firebase('https://yours.firebaseio.com/users');
var index = new Firebase('https://yours.firebaseio.com/index');
function createIndex() {
ref.once('value', function(snapshot) {
snapshot.forEach(function(userSnapshot) {
var user = userSnapshot.val();
index.child(user.age).child(userSnapshot.key()).set(true);
Object.keys(user.activities).forEach(function(activity) {
index.child(activity).child(userSnapshot.key()).set(true);
});
});
});
}
Since you want to search across all users, the code loops over all users (you should normally do this when the users are added or modified, so by listening for the child_ events). It then adds the relevant nodes to the index: one for the age and one for every category.
After running this on your data, the index node looks like this:
{
"21": {"123":true},
"30":{"124":true},
"bike":{"124":true},
"horse":{"123":true}
}
So with that you can get all users that are between 20 and 30 by:
ref.orderByKey().startAt("20").endAt("30").on('child_added'
Or all users with a "horse" activity by:
ref.orderByKey().equalTo("horse").on('child_added'

MongoDB - Updated $ref value unable to query new value

I've posted the following question which has been answered correctly:
MongoDB - Updating only $ref from DBRef field type
Despite of this when I execute the find method like this:
{ "codeId" : { "$ref" : "code" , "$id" : { "$oid" :
"4ff1c08c6ef25616ce21c4b6"}} }
The document isn't returned... Any idea why?
After the update the document is stored like this:
{ "_id" : { "$oid" : "5097ae1cd3159eb52d05574c"} , "codeId" : { "$ref"
: "code" , "$id" : { "$oid" : "4ff1c08c6ef25616ce21c4b6"}} }
By the way, using uMongo GUI, if I select the Update option over this stored document, and save it, without making any changes whatsoever, and then make the find query once again, the document is returned by the query...
Thanks
This is a clearly one of those DBRef "tweaky" things...
As a temporary (but probably correct) fix, I managed to solve this problem executing this javascript procedure:
var cursor = db.menu.find( { "codeId.$ref" : "version" } );
while( cursor.hasNext() )
{
var document = cursor.next();
db.menu.update(
document,
{ $set: {"codeId" : DBRef("code", document.codeId.$id) }},
{ upsert: false, multi: true }
);
}
Still, I won't consider this to be the best way to achieve what I want... Any other solution that involves less lines?

Categories