I'm just learning Meteor and I made a little app but I have a problem with find() and update() collection on server side
For example:
if (Meteor.isServer) {
function getCollection1(){
return collection_1.find({}).fetch({});
}
....
Meteor.methods({
start: function(id) {
datas = getCollection1();
Collection2.update({_id:id}, {$set: {datas: datas}}); //sometimes it's ok(3/4)
}
...
}
Or when I await, I have an error
if (Meteor.isServer) {
async function getCollection1(){
return await collection_1.find({}).fetch({});
}
....
Meteor.methods({
start: function(id) {
getCollection1().then(function(datas){
Rooms.update({_id: id}, {$set: {datas: datas}},function(err){
console.log(err);//error: Meteor code must always run within a fiber
});
});
}
...
}
What did I do wrong?
EDIT
it seems to work well with Fiber()
if (Meteor.isServer) {
Fiber = Npm.require('fibers')
function getCollection1(){
return collection1.find({}).fetch({});
}
function setCollection2(id){
Fiber(function() {
datas = getCollection1();
collection2.update({_id: id}, {$set: {datas: datas}},function(err){
console.log(err);
});
}).run();
}
....
Meteor.methods({
start: function(id) {
setCollection2(id);
}
...
}
With the async/await version, you do not need to use Fiber. Instead you could this Meteor function: Meteor.bindEnvironment to make it work:
// ...
getCollection1().then(Meteor.bindEnvironment(function(datas){
Rooms.update(// ...);
}));
// ...
For a more understandable explanation, you could consult this video:
What is Meteor.bindEnvironment?
Based on the code you provided, my guess is that for the first example the "Collection2.update" is taking place before GetCollection1() is completed. If this is indeed the case, then on the client side when you subscribe to the collection be sure to have a way to "wait" for the subscription to complete.
For example something like this on the client side where "start()" is called...
const handle = Meteor.subscribe( 'collection_1' );
if ( handle.ready() ) {
Meteor.call('start');
} else {
const allusers = Meteor.users.find().fetch();
onData( null, {allusers} );
}
Again, this is my best guess as you did not post the error you received with your first code chunk and I can't speak for the second you in which you've attempted to implement this.
Related
I am trying to implement a search function where a user can return other users by passing a username through a component. I followed the ember guides and have the following code to do so in my routes file:
import Ember from 'ember';
export default Ember.Route.extend({
flashMessages: Ember.inject.service(),
actions: {
searchAccount (params) {
// let accounts = this.get('store').peekAll('account');
// let account = accounts.filterBy('user_name', params.userName);
// console.log(account);
this.get('store').peekAll('account')
.then((accounts) => {
return accounts.filterBy('user_name', params.userName);
})
.then((account) => {
console.log(account);
this.get('flashMessages')
.success('account retrieved');
})
.catch(() => {
this.get('flashMessages')
.danger('There was a problem. Please try again.');
});
}
}
});
This code, however, throws me the following error:
"You cannot pass '[object Object]' as id to the store's find method"
I think that this implementation of the .find method is no longer valid, and I need to go about returning the object in a different manner. How would I go about doing this?
You can't do .then for filterBy.
You can't do .then for peekAll. because both will not return the Promise.
Calling asynchronous code and inside the searchAccount and returning the result doesn't make much sense here. since searchAccount will return quickly before completion of async code.
this.get('store').findAll('account',{reload:true}).then((accounts) =>{
if(accounts.findBy('user_name', params.userName)){
// show exists message
} else {
//show does not exist message
}
});
the above code will contact the server, and get all the result and then do findBy for the filtering. so filtering is done in client side. instead of this you can do query,
this.store.query('account', { filter: { user_name: params.userName } }).then(accounts =>{
//you can check with length accounts.length>0
//or you accounts.get('firstObject').get('user_name') === params.userName
//show success message appropriately.
});
DS.Store#find is not a valid method in modern versions of Ember Data. If the users are already in the store, you can peek and filter them:
this.store.peekAll('account').filterBy('user_name', params.userName);
Otherwise, you'll need to use the same approach you used in your earlier question, and query them (assuming your backend supports filtering):
this.store.query('account', { filter: { user_name: params.userName } });
I have a problem with updating some values in Meteor app on client-side. I'm trying to understand how ReactiveVar works.
When I use find() method on collection on client-side the site updates immediately each time I change something. I want to achieve the same effect using ReactiveVar and server-side Method. So the code below works correctly for me:
// Client
Template.body.onCreated(function appBodyOnCreated() {
this.subscribe('activities');
}
Template.body.helpers({
getCounter() {
return Activities.find({
editorId: Meteor.userId(),
'referredObject.type': 'LIST'
}).count();
}
});
But when I try to achieve the same effect with server-side Method it doesn't work correctly. Code below updates variable only once. If I want to get current value I need to refresh the page.
// Server
Meteor.methods({'activitiesCreateCount'(userId, objectType) {
check(userId, String);
check(objectType, String);
return Activities.find({
editorId: userId,
'referredObject.type': objectType
}).count();
}
});
// Client
Template.body.onCreated(function appBodyOnCreated() {
this.subscribe('activities');
this.activitiesAmount = new ReactiveVar(false);
}
Template.body.helpers({
getCounter() {
var tempInstance = Template.instance();
Meteor.call('activitiesCreateCount', Meteor.userId(), 'TODO', function(err, response) {
tempInstance.activitiesAmount.set(response);
});
return Template.instance().activitiesAmount.get();
}
});
How I can improve my code if I want always have a current value of the variable (like in the first client-side only example)?
Try to move Meteor.callto Template.body.onCreated
Something like this
// Server
Meteor.methods({'activitiesCreateCount'(userId, objectType) {
check(userId, String);
check(objectType, String);
return Activities.find({
editorId: userId,
'referredObject.type': objectType
}).count();
}
});
// Client
Template.body.onCreated(function appBodyOnCreated() {
self = this;
this.activitiesAmount = new ReactiveVar(false);
Meteor.call('activitiesCreateCount', Meteor.userId(), 'TODO', function(err, response) {
self.activitiesAmount.set(response);
});
}
Template.body.helpers({
getCounter() {
return Template.instance().activitiesAmount.get();
}
});
This is my original client code
var socket = io.connect('http://localhost:7048');
socket.on('channel', function (mess) {
console.log(mess);
});
socket.on('message', function (mess) {
console.log(mess);
});
How can I extend the original library so that you get something like this. Such code is used by pubnub.
var myPlugin = MYPLUGIN({
host: 'http://localhost:7048'
});
myPlugin.listen({
channel: 'channel',
message: function(m){console.log(m)},
error: function(m){console.log(m)}
});
myPlugin.listen({
channel: 'message',
message: function(m){console.log(m)},
error: function(m){console.log(m)}
});
myPlugin.unlisten({
channel : 'message',
});
If you're trying to make it like the code on pubnub just because pubnub uses this kind of syntax and you're used to it, I don't recommend on doing it, but if you have an API and you need to have a certain architecture then that's fine.
I recommend building a wrapper.
function MyPlugin(hostObj) {
function listen(listenObj) {
//your code here
}
function unlisten(unlistenObj) {
//your code here
}
//this makes your functions public
Object.defineProperties(this, {
"listen": {value: listen},
"unlisten": {value: unlisten}
});
return this;
}
I am implementing the tutorial on the mean stack https://www.youtube.com/watch?v=AEE7DY2AYvI
I am adding a delete feature to remove items from the database on a button click
My client side controller has the following 2 functions to add to db and remove
$scope.createMeetup = function() {
var meetup = new Meetup();
meetup.name = $scope.meetupName;
meetup.$save(function (result) {
$scope.meetups.push(result);
$scope.meetupName = '';
});
}
$scope.deleteMeetup = function() {
item = $scope.meetups[0];
console.log("deleting meetup: " + item["name"]);
Meetup.delete(item);
scope.meetups.shift();
}
My server side has the following code
module.exports.create = function (req, res) {
var meetup = new Meetup(req.body);
meetup.save(function (err, result) {
res.json(result);
});
}
module.exports.remove = function(req, res) {
console.log("GOING TO REMOVE!!!");
console.log(req.query);
item = req.query;
Meetup.remove(item, function (err, results) {
console.log("done");
console.log(err);
console.log(results);
});
}
When I run my code and if I delete an already loaded item in the list, it is removed from Mongodb just fine. But if I add an item to the list and I do not refresh the page, it results in an error at my server that appears as
GOING TO REMOVE!!!
{ '$resolved': 'true',
__v: '0',
_id: '54ec04e70398fab504085178',
name: 'j' }
done
{ [MongoError: unknown top level operator: $resolved]
name: 'MongoError',
code: 2,
err: 'unknown top level operator: $resolved' }
null
I if I refresh the page, the it gets deleted fine. But if I added the entry, angular seems to be adding a new variable $resolved. Why is that happening?
Also another question, What is the proper way to call delete? I call it now but I am not able to put a callback. I want a callback which returns and then I shift the list of items. I tried adding a callback but the code never reaches it.
ie I tried the following
/*
Meetup.delete(item, function () {
console.log("In callback!!");
console.log(returnValue);
console.log(responseHeaders);
$scope.meetups.splice(item);
});
*/
/*Meetup.delete(item,
function (returnValue, responseHeaders) {
console.log("In callback!!");
console.log(returnValue);
console.log(responseHeaders);
$scope.meetups.splice(item);
},
function (httpResponse){
// error handling here
console.log("Need to handle errors");
});
*/
I am very new to node and am confused. Any help is very, very appreciated
Looks like it possible to call item.delete instead of Meetup.delete(item). You can call same methods on model instance. It prevent sending angular properties to server.
But better to make a rest API with delete method
DELETE /meetups/:id
and send just a _id
Meetup.remove({id: item._id});
I'm using Meteor 1.0
This probably is a common beginners mistake but I can't seem so find the solution.
When I ask the server to return a collection, the results are not shown. However, I console log shows me the good results.
Here is the client helper:
Template.myProjectTips.helpers({
matchingProjects: function() {
Meteor.call('searchNearProjects', function(error, result) {
if (error) {
console.log(error.reason);
return;
} else {
var fields = [{}];
_.each(result, function(field) {
fields = field;
console.log('result: ' + fields.title);
});
return fields;
}
});
},
});
Can someone help me out with it?
First of all, your method should return a cursor, so you should remove .fetch() which in fact traverses the cursor to return an array. Cursor is natively supported and promoted in Meteor.
Meteor.methods({
searchNearProjects: function() {
return Project.find({}, {sort: {createdAt: -1}, limit: 10});
}
});
Also in your template code, you are replacing your array, instead you should be populating it. But since you are working with a live cursor, you don't need all of that _.each() traversal either. Therefore you can simply do:
Template.myProjectTips.helpers({
matchingProjects: function() {
Meteor.call('searchNearProjects', function(error, result) {
if (error) {
console.log(error.reason);
return;
} else {
return result;
}
});
}
});
But for a very simple Mongo query like this, you should not be using a Meteor.method
Instead you should publishing and subscribing like this:
Server:
Meteor.publish("nearProjects", function () {
return Project.find({}, {sort: {createdAt: -1}, limit: 10});
});
Client:
Meteor.subscribe("nearProjects");
Template.myProjectTips.helpers({
matchingProjects: function() {
return Project.find({}, {sort: {createdAt: -1}, limit: 10});
}
});
Or if you want to publish with some find criteria, you can pass in your arguments to your subscribe and publish functions as well.