Iron Router: My Subscription Doesn't Work Inside waitOn - meteor

I have a simple subscription running in Iron Router.
#route 'AdminEditor',
path: '/admin/editor/:id?'
controller: 'AdminController'
template: 'AdminRoot'
yieldTemplates:
'AdminEditor': { to: 'adminAside' }
waitOn: ->
return Meteor.subscribe 'getArticle', #params.id
The publication:
Meteor.publish 'getArticle', (id) ->
return Articles.find { 'id': id }
My database is not empty and have a single document into it:
db.articles.find().pretty()
{
"authors" : [
"dqbxgrxzehXXTbFgG"
],
"date" : ISODate("2014-10-01T20:07:48.846Z"),
"title" : "Meteor #5",
"content" : "hello",
"id" : 1,
"_id" : "WL7ygMw2jL9WnmRYZ"
}
But when I go to /admin/editor/1 and type in my chrome debugger Articles.findOne(), it doesn't return anything. I also have defined the collection in a lib folder:
#Articles = new Meteor.Collection 'articles' # run on both client and server
I know there is probably a little thing I forgot, but the subscription seems to work: when I subscribe to it from the chrome debugger and do a find, it returns the object.
Meteor.subscribe('getArticle', 1);
Articles.findOne();

Can you log the value of #params.id in the waitOn to check what you're actually sending? It could be the fact that you're sending it as a string rather than an integer (as you are in the console). If so, you just need to parseInt and it should work.

Related

AppSync BatchDeleteItem not executes properly

I'm working on a React Native application with AppSync, and following is my schema to the problem:
type JoineeDeletedConnection {
items: [Joinee]
nextToken: String
}
type Mutation {
deleteJoinee(ids: [ID!]): [Joinee]
}
In 'request mapping template' to resolver to deleteJoinee, I have following (following the tutorial from https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-dynamodb-batch.html):
#set($ids = [])
#foreach($id in ${ctx.args.ids})
#set($map = {})
$util.qr($map.put("id", $util.dynamodb.toString($id)))
$util.qr($ids.add($map))
#end
{
"version" : "2018-05-29",
"operation" : "BatchDeleteItem",
"tables" : {
"JoineesTable": $util.toJson($ids)
}
}
..and in 'response mapping template' to the resolver,
$util.toJson($ctx.result.data.JoineesTable)
The problem is, when I ran the query, I got empty result and nothing deleted to database as well:
// calling the query
mutation DeleteJoinee {
deleteJoinee(ids: ["xxxx", "xxxx"])
{
id
}
}
// returns
{
"data": {
"deleteJoinee": [
null
]
}
}
I finally able to solve this puzzle, thanks to the answer mentioned here to point me to some direction.
Although, I noticed that JoineesTable does have trusted entity/role to the IAM 'Roles' section, yet it wasn't working for some reason. Looking into this more, I noticed that the existing policy had following actions as default:
"Action": [
"dynamodb:DeleteItem",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:UpdateItem"
]
Once I added following two more actions to the list, things have started working:
"dynamodb:BatchWriteItem",
"dynamodb:BatchGetItem"
Thanks to #Vasileios Lekakis and #Ionut Trestian on this appSync quest )

meteor autocomplete server-side

I'm writing a meteor app and I'm trying to add an autocomplete feature to a search box. The data is very large and is on the server, so I can't have it all on the client. It's basically a database of users. If I'm not wrong, the mizzao:autocomplete package should make that possible, but I can't seem to get it to work.
Here's what I have on the server:
Meteor.publish('autocompleteViewers', function(selector, options) {
Autocomplete.publishCursor(viewers.find(selector, options), this);
this.ready();
});
And here are the settings I use for the search box on the client:
getSettings: function() {
return {
position: 'bottom',
limit: 5,
rules: [{
subscription: 'autocompleteViewers',
field: '_id',
matchAll: false,
options: '',
template: Template.vLegend
}],
};
}
But I keep getting this error on the client:
Error: Collection name must be specified as string for server-side search at validateRule
I don't really understand the problem. When I look at the package code, it just seems like it's testing whether the subscription field is a string and not a variable, which it is. Any idea what the problem could be? Otherwise is there a minimum working example I could go from somewhere? I couldn't find one in the docs.
Error: Collection name must be specified as string for server-side search at validateRule
You get this error because you don't specify a Collection name in quotes.
getSettings: function() {
return {
position: 'bottom',
limit: 5,
rules: [{
subscription: 'autocompleteViewers',
field: '_id',
matchAll: false,
collection: 'viewers', // <- specify your collection, in your case it is a "viewers" collection.
options: '',
template: Template.vLegend
}],
};
}
For more information please read here.
Hope this helps!

Implementing a simple search with Meteor and Iron Router

In the next phase of my Meteor journey (read: learning the ropes!), I'd like to implement a simple search based on user inputed values, then redirect to a route specific to the record returned from the server.
At the moment, I'm picking up the inputed values via this code:
Template.home.events 'submit form': (event, template) ->
event.preventDefault()
console.log 'form submitted!'
countryFirst = event.target.firstCountrySearch.value
countrySecond = event.target.secondCountrySearch.value
Session.set 'countryPairSearchInputs', [countryFirst, countrySecond]
countryPairSearchInputs = Session.get 'countryPairSearchInputs'
console.log(countryPairSearchInputs)
return Router.go('explore')
Happily, the console log returns the desired countryPairSearchInputs variable - an array of two ids. In my routes.coffee file I then have the following:
#route "explore",
path: "/explore/:_id"
waitOn: ->
Meteor.subscribe 'countryPairsSearch'
On the server side, I have:
Meteor.publish 'countryPairsSearch', getCountryPairsSearch
And finally, I have a search.coffee file in my /lib directory that defines the getCountryPairsSearch function:
#getCountryPairsSearch = ->
CountryPairs.findOne $and: [
{ country_a_id: $in: Session.get('countryPairSearchInputs') }
{ country_b_id: $in: Session.get('countryPairSearchInputs') }
]
With regards to the search function itself, I have a CountryPairs collection where each record has two ids (country_a_id and country_b_id) - the aim here is to allow users to input two countries, with the corresponding CountryPair then being returning.
I'm currently struggling to tie all the pieces together - the console output on searching is currently:
Uncaught Error: Missing required parameters on path "/explore/:_id". The missing params are: ["_id"]. The params object passed in was: undefined.
Any help would be greatly appreciated - as you can probably tell I'm new to Meteor and am still getting used to the pub/sub methodology!
Edited: mixed up client/server for the publish method when I first posted - the danger of late-night posting!
First, seems you're expecting an :id parameter on your 'explore' route.
If I understand you're case, you're not expecting any params here, so you can just delete ':id' from your route:
#route "explore",
path: "/explore/"
waitOn: ->
Meteor.subscribe 'countryPairsSearch'
or either add a params to your Router.go call:
Router.go('explore', {_id: yourIdVar});
Secondly, you're trying to use a client function: Session.get() server-side. Try to update the publication using a parameter ; or using a method.call.
client-side
Meteor.subscribe 'countryPairsSearch' countryA countryB
not sure about the coffeescript syntax, check http://docs.meteor.com/#/full/meteor_subscribe
and server-side
#getCountryPairsSearch = (countryA, countryB) ->
CountryPairs.findOne $and: [
{ country_a_id: $in: countryA }
{ country_b_id: $in: countryB }
]

Update Mongo on the client using document ID, but limiting search with another field

When updating a document which contains an array of objects, I have this function:
Template.editCompetition.events = {
'click button.promote': function() {
Competitions.update({_id: Session.get('competition_id'), 'players.user_id': this.user_id}, {$set: {'players.$.supervisor': true}});
},
};
I am seeing the error:
Uncaught Error: Not permitted. Untrusted code may only update documents by ID.
My document looks like this:
{
_id: 'aaaabbbbb',
title: 'ccccdddddd',
players: [
{
username: 'wwwww',
user_id: 'xxxxx',
supervisor: false
},
{
username: 'yyyyy',
user_id: 'zzzzz',
supervisor: false
}]
}
Isn't my query updating the document by the ID, but also searching for that array position to use the .$ notation.
How can I achieve this without using a method, which seems a bit hacky...?
You are also trying to use the player.user_id as second parameter for update query
Other option you can have to use Meteor.method.
Move Collection update code to Meteor server side method and call it from client side
On Server side,
Meteor.methods({
`update_players`: function(competition_id){
user_id = this.userId
Competitions.update({_id: competition_id, 'players.user_id': user_id}, {$set: {'players.$.supervisor': true}});
}
})
In in above code, understand use of how we fetched current userId with this.userId
and now from your click handler call this meteror method
Meteor.call('update_players')
Hope this helps

Meteor Iron-Router: why isn't this routing setup (with waitOn and data functions) working correctly?

Using Iron-Router 1.0.3 and Meteor 1.0.
I have this route defined:
Router.route('audit', {
path: '/audit/:audit_id/',
template: 'audit',
data: function() {
audit = Audits.findOne({_id: this.params.audit_id});
lineitems = LineItems.find(JSON.parse(audit.query));
return {
audit: audit,
lineitems: lineitems
}
},
waitOn: function () {
return [
Meteor.subscribe('audits'),
Meteor.subscribe('lineitems', this.params.audit_id),
]
}
});
Objects in the Audits collection have the following structure:
{
_id: 'timestamped-id-that-I-generate',
name: 'some name',
query: JSON.stringify({'$and': [list of query conditions here]})
}
When I go to this route I get the following error in my console:
Uncaught TypeError: Cannot read property 'query' of undefined
But if I go to my browser console, I can examine the Audits collections and I see that the Audit object with the appropriate _id and query exists as expected.
Incidentally, the publish method for the lineitems on the server side will simply look up the same audit object and publish the line items that match it's query.
(I have to serialize the query back and forth via JSON because otherwise the query object would contain field names that violate MongoDB regulations.)
As of this writing, Iron Router's data hook may run multiple times when a route is evaluated. You can assume it will run once before the subscriptions are ready, and again afterward. Because it will run prior to your subscriptions being ready, you need to assume that Audits.findOne will return undefined at least once. You have two choices:
Check for this.ready() in your data hook:
data: function() {
if (this.ready()) {
audit = Audits.findOne({_id: this.params.audit_id});
lineitems = LineItems.find(JSON.parse(audit.query));
return {audit: audit, lineitems: lineitems};
}
}
Use a guard:
data: function() {
audit = Audits.findOne({_id: this.params.audit_id});
if (audit && audit.query) {
lineitems = LineItems.find(JSON.parse(audit.query));
return {audit: audit, lineitems: lineitems};
}
}
A combination of the two may actually be appropriate if: (a) you don't have any audits, or (b) not all audits have a query.

Resources