I'm try to get the below publish function to work. I would like to retrieve all users who do not have a class that the current user has in their profile.classes array. What am I doing wrong here?
Meteor.publish('classes', function () {
var class = Meteor.users.find({_id: this.userId},{fields: {"profile.classes": 1}});
var users = Meteor.users.find({
roles:'is_student',
"profile.classes": { $ne : class }
}});
return users;
});
Assuming profile.classes holds an array of strings and that you want to get all users who DO NOT have a class in the current user's classes, here is some code to do what you're asking for:
Meteor.publish('classes', function ( ) {
var user = Meteor.users.findOne({_id: this.userId},{fields: {"profile.classes": 1}});
if( user && user.profile && user.profile.classes ) {
return Meteor.users.find({ roles: 'is_student', 'profile.classes': { $nin: user.profile.classes } });
} else {
return this.ready();
}
});
The important line of that code is:
return Meteor.users.find({ roles: 'is_student',
'profile.classes': { $nin: user.profile.classes } });
The key part here is the $nin. From MongoDB documentation:
$nin selects the documents where:
- the field value is not in the specified array or
- the field does not exist.
So this should select users who either don't have a profile.classes array field, or have none of the classes the current user has.
Related
I'm doing filtering on a data displayed in a view which is working correctly. I've placed a filter bar at the top of the screen where a user can filter the records. What I want to achieve is when the variable the user enters is not found in the records a function should be called
filterProducts(ev) {
this.productService.list = this.reOrderList;
const val = ev.target.value;
if (val && val.trim() !== '') {
this.productService.list = this.reOrderList.filter((item) => {
return (item.name.toLowerCase().indexOf(val.toLowerCase()) > -1);
});
} else {
// value doesn't exist console.log('call another function')
}
}
Check if any items are left in the array after the filter is complete:
if (this.productService.list.length) {
// The user's query was found in the array
} else {
// The user's query was not found in the array
}
I am trying to set some user data depending on the no.of users already in my USERS COLLECTION. This even includes a userId which should be a number.
exports.setUserData = functions.firestore.document('/users/{documentId}')
.onCreate(event => {
return admin.firestore().collection('users')
.orderBy('userId', 'desc').limit(1)
.get().then(function(snapshot) {
const user = snapshot.docs[0].data();
var lastUserId = user.userId;
var userObject = {
userId: lastUserId + 1,... some other fields here
};
event.data.ref.set(userObject, {
merge: true
});
});
});
One issue I noticed here, quickly adding 2 users result in those documents having the same userId may be because the get() query is asynchronous?
Is there a way to make this whole setUserData method synchronous?
There is no way to make Cloud Functions run your function invocations sequentially. That would also be quite contrary to the serverless promise of auto-scaling to demands.
But in your case there's a much simpler, lower level primitive to get a sequential ID. You should store the last known user ID in the database and then use a transaction to read/update it.
var counterRef = admin.firestore().collection('counters').doc('userid');
return db.runTransaction(function(transaction) {
// This code may get re-run multiple times if there are conflicts.
return transaction.get(counterRef).then(function(counterDoc) {
var newValue = (counterDoc.data() || 0) + 1;
transaction.update(counterRef, newValue);
});
});
Solution
var counterRef = admin.firestore().collection('counters').doc('userId');
return admin.firestore().runTransaction(function(transaction) {
// This code may get re-run multiple times if there are conflicts.
return transaction.get(counterRef).then(function(counterDoc) {
var newValue = (counterDoc.data().value || 0) + 1;
transaction.update(counterRef, {
"value": newValue
});
});
}).then(t => {
admin.firestore().runTransaction(function(transaction) {
// This code may get re-run multiple times if there are conflicts.
return transaction.get(counterRef).then(function(counterDoc) {
var userIdCounter = counterDoc.data().value || 0;
var userObject = {
userId: userIdCounter
};
event.data.ref.set(userObject, {
merge: true
});
});
})
});
here I'm pushing product_detail to an empty array product. At first I'm checking if the array is empty, If so the json data is pushed into the array and updated with session. If not I want to verify if the there exists an object with the id, if so it wont push it. but the condition is not becoming true. Dont know what I'm missing or I'm putting the condition wrongly
var product_details = {
product_id: product._id,
user_id: user_id,
};
if (product.length !== 0) {
if (req.session.product.forEach(function(data) {
(data.product_id == req.params._id)
})) {
return res.send("product already present ");
}
product.push(product_detail);
req.session.product = product;
return res.send(req.session.product);
}
product.push(product_detail);
req.session.product = product;
console.log(req.session);
return res.send(req.session.product);
});
Simply change your nested condition to:
var arrayTrue = true;
req.session.product.forEach(function(data) {
if(data.product_id == req.params._id){
arrayTrue = false;
}
});
if(arrayTrue){
// Doesn't exist...
}
else{
return res.send("Product already present");
}
How would I go about filtering the return of a FindOne function in Iron Router? I assume that aggregation is out of the question, but I may be wrong. I've tried many different ways that don't work. I'd like to return the id, name, and the season object that it finds a matching season_number in.
My database is setup like so:
_id
name
seasons (array)
season (object)
season_number
episodes (array)
episode (object)
episode_title
episode_number
Here's my iron router code that is currently just running a findOne function.
Router.route('/show/:_id/season/:season_number', {
name: 'viewSeasonPage', // This links to the template
data: function() { return Tv.findOne({_id:"KQBXq4nri7zssDna2", "seasons.season_number": 2}))}
});
Router.route('/show/:_id/season/:season_number', {
name: 'viewSeasonPage', // This links to the template
data: function() {
let tv = Tv.findOne({_id:"KQBXq4nri7zssDna2", "seasons.season_number": 2});
if (tv && tv.seasons) { return tv.seasons.find(function(season) { return season.season_number == 2; })
}
});
You need to filter the result to create the data object you want to return with the information you need. If your search doesn't find anything, your data is an empty object.
Router.route('/show/:_id/season/:season_number', {
name: 'viewSeasonPage',
data: function() {
// Find your object
var tv = Tv.findOne({
_id: this.params._id,
seasons: {
$elemMatch: {
season_number: this.params.season_number
}
}
});
// Fill data by filtering the correct season
var data = {};
if (tv) {
data._id = tv._id; // 1. ID
data.name = tv.name; // 2. NAME
// Find correct season in array
var season;
for (var i = tv.seasons.length - 1; i >= 0; i--) {
season = tv.seasons[i];
if (season.season_number == this.params.season_number) {
data.season = season; // 3. SEASON
}
};
}
return data;
}
});
I know it's a lot of coding, but this is for understanding the idea and the process.
I'm trying to verify if a specific record exist inside a table by a given ID. For example:
var id = 23;
db.count('products',id).done(function(count) {
if(count>0){
db.get('products',id).done(function(r) {
//Do something
});
}else{
alert('No product found');
}
});
When I try this, I get the following error: uncaught exception: null
I'd really appreciate your help Thanks!.
Your solution is almost correct.
In IndexedDB API, there is no exists method, probably because it can be emulated using count method. But count method accepts only key range, so existence test should be:
var id = 23;
db.count('products', ydn.db.KeyRange.only(id)).done(function(cnt) {
if (cnt) { // exist
} else { // no exist
}
});
Another reason, exists method don't exist in the IndexedDB api is that, get don't give error for non-existing key. So you can safely, and recommended, to do:
var id = 23;
db.get('products', id).done(function(product) {
if (product) { // exist
} else { // no exist
}
});
I would like to point out that, in these two ways to detect existence, the first method is more efficient because it avoid deserialization. So if you just need to test for existence, use first method. For retrieving a record, which may or may not exist, use second method.
EDIT:
To query a record by primary key, id, or unique secondary key, sku
/**
* #param {string} id id or sku
* #param {Function} cb callback to invoke resulting record value. If not exists in the
* database, null or undefined is returned.
*/
var getByIdOrSku = function(id, cb) {
var req = db.get('items', id);
req.done(function(item) {
if (item) {
cb(item)
} else {
db.values('items', 'SKU', ydn.db.KeyRange.only(id), 1).done(function(items) {
cb(items[0]); // may not have result
});
}
});
};
If you prefer promise way:
db.get('items', id).then(function(item) {
if (item) {
return item;
} else {
return db.values('items', 'SKU', ydn.db.KeyRange.only(id), 1).done(function(items) {
return items[0];
});
}
}).done(function(item) {
// result query as as id or SKU
console.log(item);
});