Publications with Relations - Meteor - meteor

I recently added the lepozepo:publish-with-relations package to my project and I am trying to publish a shopping cart
Meteor.publish "cart", (ops={}) ->
if ops.cotizacion and not _.isEmpty ops.cotizacion
#relations
collection:Cotizaciones
filter:
_id:ops.cotizacion
status:"new"
mappings:[
{
key:"cotizacion"
collection:CotDetails
options:
limit:25
mappings:[
{
foreign_key:"codigo"
collection:Productos
}
]
}
]
#ready()
my subscription is the following
Template.CotIzq.onCreated ->
self = this
self.autorun ->
self.subscribe 'cart'
If I add the autopublish package I can see the publication. So I know the problem is here

It doesn't look like you're passing any options through for the ops argument of your publication, and you're then checking that the ops argument isn't empty before proceeding, try either passing in the correct options or removing the check.

Related

How to configure dynamodb-to-lambda trigger using amplify framework/cli

The amplify docks here says that we can configure a lambda function as a dynamodb trigger by running **amplify add function** and selecting the "Lambda Trigger" option, but when I run the "amplify add api" (selected Python as runtime language) I am not getting the lambda trigger option, I'm only getting the "Serverless function" and "lambda layer" options.
Please help me to resolve this issue to access the feature.
docs snapshot - showing 4 options
my CLI snapshot - showing only 2 options
I know it works for nodejs runtime lambda, but I want this option for Python Lambda as well.
Just followed these steps with amplify CLI version 4.50.2.
To create a lambda function that is triggered by changes to a DynamoDB table, you can use the following command line actions, which are walked-through inside of the CLI after entering the below command:
amplify add function
Select which capability you want to add:
❯ Lambda function (serverless function)
Provide an AWS Lambda function name:
<YourFunctionsName>
Choose the runtime that you want to use:
> NodeJS # IMPORTANT: Must be NodeJS as of now, you can change this later by manually editing ...-cloudformation-template.json file inside function directory
Choose the function template you want to use
> Lambda Trigger
What event source do you want to associate with the lambda trigger
> Amazon DynamoDB Stream
Choose a DynamoDB event source option
>Use API category graphql #model backend DynamoDB table(s) in the current Amplify project
Choose the graphql #model(s)
<Select any models (using spacebar) you want to trigger the function after editing>
Do you want to trigger advanced settings
Y # IMPORTANT: If you are using a dynamodb event source based on a table defined by graphql schema, you will need to give this function read access to the api resource that contains the graphql schema that defines the table that drives the event
Do you want to access other resources in this project from your Lambda function?
y # See above, select your api that contains the data model and make sure that the function has at least read access.
After this, the other options (layer, call scheduling) are up to you.
After creating the function via the above CLI options, you can change the "Runtime" field inside the -cloudformation-template.json file inside function directory, eg if you want a python lambda function change the runtime to "python3.8". You will also need to create a file called index.py inside your function's directory which has a handler(event, context) function. See example below:
import json
def handler(event, context):
print("Triggered via DynamoDB")
print(event)
return json.dumps({'status_code': 200, "message": "Received from DynamoDB"})
After making these edits, you can run amplify push and, if you open your fxn in the management console online, it should show an attached dynamoDB stream.
Doesn't appear to be available anymore in the CLI codebase - see Supported-service.json deleted and replaced by supported-services.ts
https://github.com/aws-amplify/amplify-cli/commit/607ae21287941805f44ea8a9b78dd12d16d71f85#diff-a0fd8c5607fd81977cb4745b9af3af2c6649ded748991bf9968a7d782b000c6b
https://github.com/aws-amplify/amplify-cli/commits/4e974007d95c894ab4108a2dff8d5996e7e3ce25/packages/amplify-category-function/src/provider-utils/supported-services.ts
Select nodejs and you will be able to view lambda trigger
just add the following to {YOUR_FUNCTION_NAME}-cloudformation-template.json, remember to replace (YOUR_TABLE_NAME) to your table name.
"LambdaTriggerPolicyPurchase": {
"DependsOn": [
"LambdaExecutionRole"
],
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "amplify-lambda-execution-policy-Purchase",
"Roles": [
{
"Ref": "LambdaExecutionRole"
}
],
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:DescribeStream",
"dynamodb:GetRecords",
"dynamodb:GetShardIterator",
"dynamodb:ListStreams"
],
"Resource": {
"Fn::ImportValue": {
"Fn::Sub": "${apilanguageGraphQLAPIIdOutput}:GetAtt:(YOUR_TABLE_NAME):StreamArn"
}
}
}
]
}
}
},
"LambdaEventSourceMappingPurchase": {
"Type": "AWS::Lambda::EventSourceMapping",
"DependsOn": [
"LambdaTriggerPolicyPurchase",
"LambdaExecutionRole"
],
"Properties": {
"BatchSize": 100,
"Enabled": true,
"EventSourceArn": {
"Fn::ImportValue": {
"Fn::Sub": "${apilanguageGraphQLAPIIdOutput}:GetAtt:(YOUR_TABLE_NAME):StreamArn"
}
},
"FunctionName": {
"Fn::GetAtt": [
"LambdaFunction",
"Arn"
]
},
"StartingPosition": "LATEST"
}
},
i got them by creating a dummy function using the template that shows up after you choose nodejs and checking compare its -cloudformation-template.json with my own function

Publishing role names into a table Meteor alanning:roles and aldeed:tabular

I'm having trouble displaying the created roles in a table. I'm using alanning:roles and aldeed:tabular. To create the table I have:
TabularTables.RolesAdmin = new Tabular.Table({
name: "Roles",
collection: Meteor.roles,
pub:"rolesadmin",
allow: function (userId) {
return Roles.userIsInRole(userId, 'admin');
},
columns: [
{
data: "name",
title: "Role Name",
},
],
});
And the publication looks like this:
Meteor.publish( 'rolesadmin', function() {
return Meteor.roles.find( {}, { fields: { "name": 1 } } );
});
When running the app the table only displays "Processing..." thus there is an error and it is not able at access/find the data?
I'm getting the following exception in the server terminal:
Exception from sub rolesadmin id 6c6x3mDzweP8MbB9A
Error: Did not check() all arguments during publisher 'rolesadmin'
If I check in mongo db.roles.find(), there is no role with 6c6x3mDzweP8MbB9A id. What does this error refer to?
From the meteor-tabular docs:
To tell Tabular to use your custom publish function, pass the
publication name as the pub option. Your function:
MUST accept and check three arguments: tableName, ids, and fields
MUST publish all the documents where _id is in the ids array.
MUST do any necessary security checks
SHOULD publish only the fields listed in the fields object, if one is > provided.
MAY also publish other data necessary for your table
So it looks like you'll need to account for those three arguments mentioned in the documentation appropriately. I'm not sure you actually need a custom pub for this, though, based on what you are publishing.

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 }
]

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.

Not updating Meteor.users.update with insecure package and autopublish on

I've got the following smart-packages installed:
standard-app-packages
autopublish
insecure
preserve-inputs
bootstrap-3
accounts-base
accounts-password
jquery
accounts-ui-bootstrap-3
iron-router
I'm trying to update the email address for a user, and since i've got the insecure and autopublish packages installed, i thought i could just do that like this:
Template.settings.events({
'click #update': function (evt, tmpl) {
evt.preventDefault();
var email = tmpl.find("#inputEmail").value;
Meteor.users.update({_id:Meteor.userId()}, {$set:{"emails":[{address:email}]}});
}
});
But i keep getting: update failed: Access denied
Mabye this comment out of the docs helps you.
Users are by default allowed to specify their own profile field with Accounts.createUser and modify it with Meteor.users.update. To allow users to edit additional fields, use Meteor.users.allow. To forbid users from making any modifications to their user document
You try to change the emails field. At first the emails field should be ( if you want to have the email public ) in profile folder. So you have to do something like
$set: {
profile: {
emails: {
}
}
}
If you change another field outside of profile you have to define allow-rules.

Resources