firebase grab by orderByChild then update results key - javascript

So i have this query and currently collects all the data with materialName equals to gold. I wanted change all to false.
// materialName = "gold" for example
database.ref('/app/posts').orderByChild('material').startAt(materialName).endAt(materialName).once('value', function (snapshot) {
const materials = snapshot.val();
})
I have tried something like this:
database.ref('/app/posts').orderByChild('material').startAt(materialName).endAt(materialName).once('value', function (snapshot) {
database.ref('/app/posts').update({material: false});
})
also I have tried this:
const newData = Object.assign({}, materials, {material: false});
// but this updates outside of the post, result will be:
"posts" : {
"material": false,
"post-1503586" : {
"title": "sample title",
"material" : "gold"
},
"post-9172991" : {
"title": "sample title",
"material" : "silver"
}
}
sample json:
"posts" : {
"post-1503586" : {
"title": "sample title",
"material" : "gold"
},
"post-9172991" : {
"title": "sample title",
"material" : "silver"
}
}

You need to loop over the results (since there can be multiple matching nodes) and then update each:
database.ref('/app/posts')
.orderByChild('material')
.equalTo(materialName)
.once('value', function (snapshot) {
snapshot.forEach(function(child) {
child.ref.update({material: false});
});
});
You'll also note that I changed your .startAt().endAt() to an equalTo(), which gives the same results with less code.

Related

Firebase query delete specific uid Real Time Database (Javascript)

I have this data on my firebase:
transportation: {
"car" : {
"bus" : {
"toyota" : true,
"bmw" : true
},
"suv" : {
"honda" : true,
"toyota" : true,
}
}
}
I want to delete all "toyota" data so that my data looks like this:
transportation: {
"car" : {
"bus" : {
"bmw" : true
},
"suv" : {
"honda" : true,
}
}
}
The best possible way to do is check the value using loop in Javascript manually and delete if it's "toyota".
var firebaseRef= firebase.database().ref('transportation/');
firebaseRef.on("value", function(data)){
var datKey=data.key;
firebase.database().ref('transportation/'+datKey).on("value",function(childData)){
var childDataKey=childData.key;
firebase.database().ref('transportation/'+datKey+'/'+childDataKey+'/').on("value",function(data)){
firebase.database().ref('transportation/'+dataKey+'/'+childDataKey+'toyota').remove();
}
}
}

Query in firebase usining angular 4 and angularFire 2

I try to query a list from 5000 products that have property = 110571 is not do anything
I use angularfire 2 but for the last 5 hours, I don't get anything help me.
What is the best way to do that?
This is the object in Firebase database
"products" : {
1753: {
"name" : "sprite",
"custom_id" : 534253,
"description" : "some small description"
},
1754: {
"name" : "coca cola",
"custom_id" : 110571, <---- i want to find if this node from 5000 products exist in database and if exist i want to return true
"description" : "some small description"
},
1755: {
"name" : "fanta",
"custom_id" : dsgfsdfds,
"description" : "some small description"
},
}
This is the function that I use
x = 1754;
check_if_product_code_exist(x) {
console.log(x);
this.searchSubject.next(x);
// this.products = this.db.list('/products') as FirebaseListObservable<Product[]>;
this.products = this.db.list('/products', { query: {
orderByChild: 'custom_id',
equalTo: this.searchSubject,
limitToFirst: 1
}} ) as FirebaseListObservable<Product[]>;
console.log(this.products);
return this.products;
}

How to get element from collection in Meteor if it multi-dimensional array or object or both?

I have collection "groups". like this:
{
"_id" : "e9sc7ogDp8pwY2uSX",
"groupName" : "one",
"creator" : "KPi9JwvEohKJsFyL4",
"eventDate" : "",
"isEvent" : true,
"eventStatus" : "Event announced",
"user" : [
{
"id" : "xfaAjgcSpSeGdmBuv",
"username" : "1#gmail.com",
"email" : "1#gmail.com",
"order" : [ ],
"price" : [ ],
"confirm" : false,
"complete" : false,
"emailText" : ""
},
...
],
...
"buyingStatus" : false,
"emailTextConfirmOrder" : " With love, your Pizzaday!! "
}
How can I get a value of specific element? For example i need to get value of "Groups.user.confirm" of specific group and specific user.
I tried to do so in methods.js
'pizzaDay.user.confirm': function(thisGroupeId, thisUser){
return Groups.find({ _id: thisGroupeId },{"user": ""},{"id": thisUser}).confirm
},
but it returns nothing.
Even in mongo console I can get just users array using
db.groups.findOne({ _id: "e9sc7ogDp8pwY2uSX"},{"user": ""})
The whole code is github
http://github.com/sysstas/pizzaday2
Try the following query:-
db.groups.aggregate(
[
{
$match:
{
_id: thisGroupeId,
"user.id": thisUser
}
},
{
$project:
{
groupName : 1,
//Add other fields of `user` level, if want to project those as well.
user:
{
"$setDifference":
[{
"$map":
{
"input": "$user",
"as": "o",
"in":
{
$eq : ["$$o.id" , thisUser] //Updated here
}
}
},[false]
]
}
}
}
]);
The above query will give the object(s) matching the query in $match inside user array. Now you can access any field you want of that particular object.
'pizzaDay.user.confirm': function(){
return Groups.findOne({ _id: thisGroupeId }).user.confirm;
I resolved it using this:
Template.Pizzaday.helpers({
confirm: function(){
let isConfirm = Groups.findOne(
{_id: Session.get("idgroupe")}).user.filter(
function(v){
return v.id === Meteor.userId();
})[0].confirm;
return isConfirm;
},
});
But I still think that there is some much elegant way to do that.

Meteor + MongoDB: How to get nested data?

I'm new to Meteor and trying to figure out this issue I have.
I'm trying to load data from the Lessons collection based on the route being passed. e.g if /courses/level1/lesson1/1a is passed then show data
Unfortunately this doesn't work.
Am I on the right path or is there a better way of doing this?
Collection
{
"_id": "YSgr3fvjpEBn7ncRa",
"courseId": "level1",
"lesson": [
{
"lessonId": "lesson1",
"freeLesson": true,
"title": "Lesson 1",
"eachLesson": [
{
"eachLessonId": "1a",
"title": "This is (masculine)",
"video": "839843"
},
{
"eachLessonId": "1b",
"title": "That is (masculine)",
"video": "839843"
},
{
"eachLessonId": "1c",
"title": "This is (feminine)",
"video": "839843"
},
{
"eachLessonId": "1d",
"title": "That is (feminine)",
"video": "839843"
},
{
"eachLessonId": "1e",
"title": "Getting to know you",
"video": "839843"
}
]
}
]
}
Routes
Router.route("courses/:courseId/:lessonId/:eachLessonId", {
path:"/courses/:courseId/:lessonId/:eachLessonId",
layoutTemplate: "layoutLessons",
template:"lessons",
onBeforeAction:function(){
var currentUser = Meteor.userId();
if (currentUser) {
Session.set('courseId', this.params.courseId);
Session.set('lessonId', this.params.lessonId);
Session.set('eachLessonId', this.params.eachLessonId);
this.next();
} else {
Router.go('/')
}
},
});
Template helper
Template.lessons.onCreated(function(){
Meteor.subscribe('listLessons');
});
Template.lessons.helpers({
currentLesson: function() {
var currentLesson = Session.get('eachLessonId');
return Lessons.find({"lesson.eachLesson.eachLessonId" : currentLesson});
},
});
HTML
{{#each currentLesson}}
{{title}}
{{video}}
{{/each}}
Instead of storing courseId, lessonId and eachLessonId as Session values, you could use the Iron Router's waitOn and data option.
For example, you could rewrite your route as follows:
Router.route('/courses/:courseId/:lessonId/:eachLessonId', {
name: 'lessons',
layoutTemplate: 'layoutLessons',
template: 'lessons',
onBeforeAction: function() {
let currentUser = Meteor.user();
if (currentUser) this.next();
else Router.go('/');
},
data: function() {
var doc = Lessons.findOne({
"courseId": this.params.courseId,
"lesson.lessonId": this.params.lessonId,
"lesson.eachLesson.eachLessonId": this.params.eachLessonId
});
if (doc) {
var lesson = {};
var lessonId = this.params.eachLessonId;
_.each(doc.lesson, function(i) {
lesson = _.find(i.eachLesson, function(j) {
return j.eachLessonId == lessonId;
});
});
return lesson;
}
return {};
},
waitOn: function() {
return [
Meteor.subscribe('lesson', this.params.courseId, this.params.lessonId, this.params.eachLessonId)
];
}
});
This should set the data context to the requested eachLesson object. However, you may consider setting the data context to a document in the Lessons collection and then just picking certain eachLesson objects. In addition, you should create a publish function which returns just the requested Lessons document and not all of them, like you probably do now in your listLessons publication. You can pass all IDs as arguments to the corresponding publish function.

Mongo Aggregate: how to compare with a field from another collection?

I am trying to implement a function that collects unread messages from an articles collection. Each article in the collection has a "discussions" entry with discussion comment subdocuments. An example of such a subdocument is:
{
"id": NumberLong(7534),
"user": DBRef("users", ObjectId("...")),
"dt_create": ISODate("2015-01-26T00:10:44Z"),
"content": "The discussion comment content"
}
The parent document has the following (partial) structure:
{
model: {
id: 17676,
title: "Article title",
author: DBRef("users", ObjectId(...)),
// a bunch of other fields here
},
statistics: {
// Statistics will be stored here (pageviews, etc)
},
discussions: [
// Array of discussion subdocuments, like the one above
]
}
Each user also has a last_viewed entry which is a document, an example is as follows:
{
"17676" : "2015-01-10T00:00:00.000Z",
"18038" : "2015-01-10T00:00:00.000Z",
"18242" : "2015-01-20T00:00:00.000Z",
"18325" : "2015-01-20T00:00:00.000Z"
}
This means that the user has looked at discussion comments for the last time on January 10th 2015 for articles with IDs 17676 and 18038, and on January 20th 2015 for articles with IDs 18242 and 18325.
So I want to collect discussion entries from the article documents, and for article with ID 17676, I want to collect the discussion entries that were created after 2015-01-10, and for article with ID 18242, I want to show the discussion entries created after 2015-01-20.
UPDATED
Based on Neil Lunn's reply, the function I have created so far is:
function getUnreadDiscussions(userid) {
user = db.users.findOne({ 'model.id': userid });
last_viewed = [];
for(var i in user.last_viewed) {
last_viewed.push({
'id': parseInt(i),
'dt': user.last_viewed[i]
});
}
result = db.articles.aggregate([
// For now, collect just articles the user has written
{ $match: { 'model.author': DBRef('users', user._id) } },
{ $unwind: '$discussions' },
{ $project: {
'model': '$model',
'discussions': '$discussions',
'last_viewed': {
'$let': {
'vars': { 'last_viewed': last_viewed },
'in': {
'$setDifference': [
{ '$map': {
'input': '$$last_viewed',
'as': 'last_viewed',
'in': {
'$cond': [
{ '$eq': [ '$$last_viewed.id', '$model.id' ] },
'$$last_viewed.dt',
false
]
}
} },
[ false ]
]
}
}
}
}
},
// To get a scalar instead of a 1-element array:
{ $unwind: '$last_viewed' },
// Match only those that were created after last_viewed
{ $match: { 'discussions.dt_create': { $gt: '$last_viewed' } } },
{ $project: {
'model.id': 1,
'model.title': 1,
'discussions': 1,
'last_viewed': 1
} }
]);
return result.toArray();
}
The whole $let thing, and the $unwind after that, transforms the data into the following partial projection (with the last $match commented out):
{
"_id" : ObjectId("54d9af1dca71d8054c8d0ee3"),
"model" : {
"id" : NumberLong(18325),
"title" : "Article title"
},
"discussions" : {
"id" : NumberLong(7543),
"user" : DBRef("users", ObjectId("54d9ae24ca71d8054c8b4567")),
"dt_create" : ISODate("2015-01-26T00:10:44Z"),
"content" : "Some comment here"
},
"last_viewed" : ISODate("2015-01-20T00:00:00Z")
},
{
"_id" : ObjectId("54d9af1dca71d8054c8d0ee3"),
"model" : {
"id" : NumberLong(18325),
"title" : "Article title"
},
"discussions" : {
"id" : NumberLong(7554),
"user" : DBRef("users", ObjectId("54d9ae24ca71d8054c8b4567")),
"dt_create" : ISODate("2015-01-26T02:03:22Z"),
"content" : "Another comment here"
},
"last_viewed" : ISODate("2015-01-20T00:00:00Z")
}
So far so good here. But the problem now is that the $match to select only the discussions created after the last_viewed date is not working. I am getting an empty array response. However, if I hard-code the date and put in $match: { 'discussions.dt_create': { $gt: ISODate("2015-01-20 00:00:00") } }, it works. But I want it to take it from last_viewed.
I found another SO thread where this issue has been resolved by using the $cmp operator.
The final part of the aggregation would be:
[
{ /* $match, $unwind, $project, $unwind as before */ },
{ $project: {
'model': 1,
'discussions': 1,
'last_viewed': 1,
'compare': {
$cmp: [ '$discussions.dt_create', '$last_viewed' ]
}
} },
{ $match: { 'compare': { $gt: 0 } } }
]
The aggregation framework is great, but it takes quite a different approach in problem-solving. Hope this helps anyone!
I'll keep the question unanswered in case anyone else has a better answer/method. If this answer has been upvoted enough times, I'll accept this one.

Categories