I have an Amplify application, using a DynamoDB table with ~50 items and accessing it via a React app.
The initial (simplified) model:
type Video #model
#key(name: "ByOrganization", fields: ["videoOrganizationId", "id"], queryField: "videosByOrganization")
{
id: ID!
createdAt: AWSDateTime
title: String!
season: Int
episode: Int
owner: String
editor: String
organization: Organization #connection
videoOrganizationId: ID
}
on the code I call this query on an Apollo React component:
<Query
query={query}
variables={{
{
limit: 100,
},
}}
pollInterval={5000}
>
{children}
</Query>);
The limit of 100 items should be enough to bring all items from the database, however, it is not what happens, and it limit it to a number of items (~20-30 items)
I have tried adding different indexes to the table:
#key(name: "ByOrganizationSortedByCreated", fields: ["videoOrganizationId", "createdAt"], queryField: "videosByOrganizationSortedByCreated")
#key(name: "ByOrganizationSortedByTitle", fields: ["videoOrganizationId", "title"], queryField: "videosByOrganizationSortedByTitle")
#key(name: "ByOrganizationSortedByTitleSeasonEpisode", fields: ["videoOrganizationId", "title", "season", "episode"], queryField: "videosByOrganizationSortedByTitleSeasonEpisode")
None of them have worked
Some items that clearly should be returned on my query are left behind
I also was trying to find any reference about limitatinos on DynamoDb number of returned items, or some odd behaviour that I'm not aware of... no success
There is also some super weird behaviours
ie: if I just add a sortDirection: 'DESC', it returns less results!
Does anyone has any idea why is this happening?
Related
I am looking to implement a query named driversByActiveStatus that returns only the active, inactive, or all drivers respectively for the following Driver type,
type Driver
#model
#auth(rules: [
{allow: private}
])
#key(name: "byLastName", fields: ["lastName", "id"], queryField: "driversByLastName")
#key(name: "byActiveStatus", fields: ["active", "id"], queryField: "driversByActiveStatus") {
id: ID!
firstName: String!
lastName: String!
# computed field that is calculated based on startDate and endDate
# true if startDate < currentDate < endDate
# false if currentDate < startDate || current > endDate
active: Boolean
startDate: AWSDateTime!
endDate: AWSDateTime!
}
The query driversByActiveStatus should work as follows,
it returns all the drivers if the active parameter is null
it returns only the active drivers if the active parameter is true (an active driver is a DynamoDB record where the current date is between its startDate and endDate, i.e., startDate < currentDate < endDate)
it returns only the inactive drivers if the active parameter is false
What would be the best way to achieve this in AWS Amplify?
From what I read on https://docs.amplify.aws/cli/ it looks like it may be possible to implement the query by overwriting the auto-generated VTL resolvers Query.driversByActiveStatus.req.vtl and Query.driversByActiveStatus.res.vtl, and replacing the active field value with a calculated value based on startDate and endDate in the returned result set in the result mapping resolver.
Has anyone implemented something similar? If so can you please shed some lights or share the code snippet as there is only limited documentation on AppSync VTL resolvers.
I'm trying to execute an update against a dynamoose model. Here's the docs on calling model.update
Model.update(key[, updateObj[, settings]],[ callback])
key can be a string representing the hashKey or an object containing the hashKey & rangeKey.
My schema has both a hash key (partition key) and range key (sort key) like this:
// create model
let model = dynamoose.model(
"SampleStatus",
{
id: {
type: String,
hashKey: true,
},
date: {
type: Date,
rangeKey: true,
},
status: String,
});
I've created an object like this (with a fixed timestamp for demoing)
let timestamp = 1606781220842; // Date.Now()
model.create({
id: "1",
date: new Date(timestamp),
status: "pending",
});
I'd like to be able to update the status property by referencing just the id property like this:
model.update({id: "1"}, {status: "completed"})
// err: The provided key element does not match the schema
model.update("1", {status: "completed"})
// err: Argument of type 'string' is not assignable to parameter of type 'ObjectType'
But both result in the shown errors:
I can pass in the full composite key if I know the timestamp, so the following will work:
let timestamp = 1606781220842; // Date.Now()
model.update({ id: "1", date: timestamp }, { status: "completed" });
However, that requires me holding onto the timestamp and persisting alongside the id.
The ID field, in my case, should, by itself, be unique, so I don't need both to create a key, but wanted to add the date as a range key so it was sortable. Should I just update my schema so there's only a single hash key? I was thinking the docs that said a "`key can be a string representing the hashkey" would let me just pass in the ID, but that throws an error on compile (in typescript).
Any suggestions?
The solution here is to remove the rangeKey from the date property.
This is because in DynamoDB every document/item must have a unique “key”. This can either be the hashKey or hashKey + rangeKey.
Since you mention that your id property is unique, you probably want to use just the hashKey as the key, which should fix the issue.
In your example there could have been many documents with that id, so DynamoDB wouldn’t know which to update.
Don’t forget that this causes changes to your table so you might have to delete and recreate the table. But that should fix the problem you are running into.
Logically there is nothing stopping you than inserting more than 1 entry into the same partition (in your case the unique id). You could insert more than one item with the same id, if it had a different date.
Therefore if you want to get an item by only its partition key, which is really a unique ID, you need to use a query to retrieve the item (as opposed to a GET), but the return signature will be a collection of items. As you know you only have one item in the partition, you can take the first item, and specify a limit of 1 to save RCU.
// create model
let model = dynamoose.model(
"SampleStatus",
{
id: {
type: String,
hashKey: true,
"index": {
"name": "index_name",
"rangeKey": "date",
}
},
date: {
type: Date
},
status: String,
});
You have to tell the schema that hashKey and range are one partition key.
Ref: https://dynamoosejs.com/guide/Schema#index-boolean--object--array
I'm using meteor simple schema, and autoform. I would like to have a reference to one type of object in the schema of the other. The two schemas are defined in separate files, I would also like to populate autoform with a dropdown of the possible references, and I'm unclear how to do this.
I've tried
venue:{
type: Venues,
label: "Venue",
},
and
venue:{
type: SimpleSchema.Venues,
label: "Venue",
},
and neither works
First you have to define your schema like this:
VenueSchema = new SimpleSchema({
title: {
type: String,
label: "Title",
max: 200
}
})
Than you can in another schema declare an attribute Venue
CustomerSchema = new SimpleSchema({
venue: {
type: VenueSchema
},
//an array of venues
venues: {
type: [VenueSchema],
minCount: 1
}
});
Take a look on basic usage of simpleSchema docs -> https://github.com/aldeed/meteor-simple-schema#basic-usage
I hope that helps.
I set up the aggregation rule:
{{ object.experienceId }}
on a notification feed in getstream.io expecting it to aggregate based on the object.experienceId, but instead it seems to aggregate everything into one, regardless of object.experienceId. Am I mis-understanding how aggregation works? What could be the issue?
var activity = {
time: new Date(),
verb: 'created',
actor: { id: 1, name: 'User One' },
object: {
id: 2,
experienceId: 12,
caption: 'Moment 1',
photo:
{ id: '314e00a2-2455-11e5-b696-feff819cdc9f',
mainColor: 'ff3333',
width: 1000,
height: 400 },
createdBy: {
id: 1, name: 'User One'
},
type: 'Moment' },
context: 'http://derbyapp.co'
};
notifications.addActivity(activity,
The reason why this is not working is because the object field is expected to be a string (http://getstream.io/docs/#add-remove-activities), thus within the aggregation rule you can not reference properties of activities object field. There are multiple solutions to this problem.
First you could supply the experienceId as a separate property of the activity object, so you can use the aggregation template {{ experienceId }}, since all the additional properties provided to an activity can be used in the aggregation rule (http://getstream.io/docs/#aggregated-feeds).
Second you could supply an object on any additional field of the activity, for instance item. Additional fields can reference their child properties thus you could use aggregation rule {{ item.experienceId }}. But beware not to send data to the getstream.io API that is not actually needed at getstream.io's end, in this example you could also send the object's id field, instead of the entire object, and retrieve the object from your local database once you retrieve activities from the API (The same holds for the actor field). If you do not want to take care of the logic needed for this you could use one of getstream's integration libraries (there are libraries for rails/django/laravel etc.).
var activity = {
time: new Date(),
verb: 'created',
actor: 1,
object: '1',
experienceId: 12
};
I've been struggling with this for a couple of hours and I can't find a good solution so maybe someone can shed a light on this.
I have a simple schema like this:
var groupschema = new SimpleSchema({
name: {
label: 'Name',
type: String
},
description: {
label: 'Description',
type: String
}
}
And I have another one:
var itemschema = new SimpleSchema({
name: {
label: 'Type:',
type: String
},
details: {
label: 'Details',
type: String
},
group: [groupschema] // <--- this is my main interest
}
If I use the above code sample AutoForm will generate an "inner form" which is quite cool actually for some puporse (e.g. for a contact to have an array of adresses or phone numbers) but for me I would like a drop-down select with the name of the group and when I click on the Insert/Update button (depending on the current form) I would like to add the whole group document to the inserted/updated item document as a subdocument.
Something like this will be inserted to the mongodb:
{
_id: the generated mongoid,
name: "This is a type",
details: "There are some thing to know about this type",
group:{
name: "Cool group",
description: "This is a really cool group"
}
}
The actual documents are far more complicated the above example is just an oversimplified version.
I've stopped writing this question yesterday and tried to do my own version.
My - half baked - solution is:
introducing a new field in the schema named groupselect (type string, autoform type: select)
populate it's contents with a Collection.find().map() lookup
groupselect: {
type: String,
label: 'Group',
optional: true,
blackbox: true,
autoform:{
type: "select",
options : function() {
return Issuegroup.find().map(function (c) {
return {label: c.name , value: c._id};
});
}
}
},
using autoform hooks before insert I assign the subdocument to the real fiel group = Group.find({_id:doc.groupselect}) and I remove the helper field from the doc
using the same technique in the before update hook also for an update form
The problem I seem to be unable to solve in a clean way is to set the default value of the helper field 'groupselect' when the update form displays. I've tried the docToForm hooks but no luck.
Isn't this somehow a very common problem? I imagine there has to be a proper solution for this so I bet that I am missing something very obvious and hopefully someone will point it out for me.
Thanks