Related
I have a problem with the model flutter project that I have. I get an error:
the argument type 'Object?' can't be assigned to the parameter type 'String'.
the argument type 'Object?' can't be assigned to the parameter type 'String'.
DropdownButtonFormField(
itemHeight: 50,
decoration: InputDecoration(border: InputBorder.none),
onChanged: (dynamic value) {
setState(() {
selectedCategory = value;
});
},
onSaved: (dynamic value) {
setState(() {
selectedCategory = value;
});
},
value: selectedCategory,
hint: Text('Select Category'),
items: categories.map((f) {
return DropdownMenuItem(
child: Text(f), //here is the error showing like : the argument type 'categoryData' cant be assigned to the parameter type String
value: f,
);
}).toList()));
category data section
class CategoryData {
String? id;
String? name;
String? image;
DateTime? createdAt;
DateTime? updatedAt;
CategoryData({this.id, this.name, this.image, this.createdAt, this.updatedAt});
factory CategoryData.fromJson(Map<String, dynamic> json) {
return CategoryData(
id: json[CommonKeys.id],
name: json[CategoryKeys.name],
image: json[CategoryKeys.image],
createdAt: json[CommonKeys.createdAt] != null ? (json[CommonKeys.createdAt] as Timestamp).toDate() : null,
updatedAt: json[CommonKeys.updatedAt] != null ? (json[CommonKeys.updatedAt] as Timestamp).toDate() : null,
);
}
Map<String, dynamic> toJson({bool toStore = true}) {
final Map<String, dynamic> data = new Map<String, dynamic>();
data[CommonKeys.id] = this.id;
data[CategoryKeys.name] = this.name;
data[CategoryKeys.image] = this.image;
data[CommonKeys.createdAt] = this.createdAt;
data[CommonKeys.updatedAt] = this.updatedAt;
return data;
}
}
Thanks for the answer.
I have an ASP.NET Core Web API and a React client. I'm trying to build admin dashboard with React-Admin. My problem is when I receive the data from server, my object are with property Id (uppercase), then in console I'm getting an error
The response to 'getList' must be like { data : [{ id: 123, ...}, ...] }, but the received data items do not have an 'id' key
I tried making new test class with property id (lowercase) in my server and then the problem is gone.
How can I fix this issue?
This is my test class and its working.
public class CityModel
{
public string id { get; set; }
public string Name { get; set; }
}
[HttpGet("Cities")]
public CityModel[] GetCities()
{
var city1 = new CityModel()
{
id = "ahsxge",
Name = "Berlin"
};
var city2 = new CityModel()
{
id = "axhdagw",
Name = "London"
};
var list = new List<CityModel>();
list.Add(city1);
list.Add(city2);
Response.Headers.Add("Access-Control-Expose-Headers", "X-Total-Count");
Response.Headers.Add("X-Total-Count", list.Count.ToString());
return list.ToArray();
}
This is my component in react :
const AppAdmin = () => {
const jwt = localStorage.getItem("jwt");
const httpClient = (url, options = {}) => {
options.user = {
authenticated: true,
token: 'Bearer ' + jwt
};
return fetchUtils.fetchJson(url, options);
};
const dataProvider = jsonServerProvider('https://localhost:44366/api', httpClient);
dataProvider.getList('Cities/Cities', {
pagination: { page: 1, perPage: 15 },
sort: { field: 'Name', order: 'ASC' },
})
.then(response => console.log(response));
return (
<Admin dataProvider={dataProvider}>
<Resource name='Cities/Cities' list={CitiesList} />
</Admin>
)
}
export default AppAdmin
You can configure the json converter to use camelCase serialization int the ConfigureServices method in the Startup.cs file the following way:
services
.AddControllers()
.AddJsonOptions(opts =>
{
opts.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
})
This way you can use PascalCase properties in your c# code (which you should do), but your client will recieve camelCase json properties.
I am trying to parse this API response below and saving the response in a sqlite database. But getting this error message in the saving process.. And I think it happens because I cant properly create this model file. Can't figure it out how to implement 2 class within the "Map<String, Object?> toJson()" section.
Error:
Invalid argument [{id: 1, name: İstanbul Ayasofya Müzesi, session_time: 12, distId: AYS, photo: https://api.thevoiceofmuseums.com/storage/contents/museums/1.jpeg, address: null, lat: null, long: null, sectionId: AYS01, email: null, updated_at: 2019-07-20T13:42:53.000, created_at: 2019-06-20T02:27:21.000}, {id: 2, name: İstanbul Topkapı Sarayı Müzesi, session_time: 12, distId: TPK01, photo: https://api.thevoiceofmuseums.com/storage/contents/museums/2.jpeg, address: null, lat: null, long: null, sectionId: TPK01, email: null, updated_at: 2019-07-20T13:44:12.000, created_at: 2019-06-21T14:11:43.000}, {id: 3, name: İstanbul Topkapı Sarayı - Harem Dairesi, session_time: 12, distId: TPK02, photo: https://api.thevoiceofmuseums.com/storage/contents/museums/3.jpeg, address: null, lat: null, long: null, sectionId: TPK02, email: null, updated_at: 2019-07-20T13:44:22.000, created_at: 2019-06-21T14:12:48.000}, {id: 4, name: İstanbul Topkapı Sarayı Müzesi ve Harem Dairesi, session_time: 12, di
E/flutter ( 7093): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: DatabaseException(java.util.HashMap cannot be cast to java.lang.Integer) sql 'INSERT INTO museums_list.db (data) VALUES (?)' args
Table View screenshot:
Here is my endpoint response:
{
"data": [
{
"id": 1,
"name": "İstanbul Ayasofya Müzesi",
"session_time": 12,
"distId": "AYS",
"photo": "https://api.thevoiceofmuseums.com/storage/contents/museums/1.jpeg",
"address": "null",
"lat": "null",
"long": "null",
"sectionId": "AYS01",
"email": "null",
"updated_at": "2019-07-20 13:42:53",
"created_at": "2019-06-20 02:27:21"
},
{
"id": 2,
"name": "İstanbul Topkapı Sarayı Müzesi",
"session_time": 12,
"distId": "TPK01",
"photo": "https://api.thevoiceofmuseums.com/storage/contents/museums/2.jpeg",
"address": "null",
"lat": "null",
"long": "null",
"sectionId": "TPK01",
"email": "null",
"updated_at": "2019-07-20 13:44:12",
"created_at": "2019-06-21 14:11:43"
},
{
"id": 3,
"name": "İstanbul Topkapı Sarayı - Harem Dairesi",
"session_time": 12,
"distId": "TPK02",
"photo": "https://api.thevoiceofmuseums.com/storage/contents/museums/3.jpeg",
"address": "null",
"lat": "null",
"long": "null",
"sectionId": "TPK02",
"email": "null",
"updated_at": "2019-07-20 13:44:22",
"created_at": "2019-06-21 14:12:48"
}
]
}
model file:
final String tableMuseums = 'MuseumsListTable';
// column names for database
class MuseumsFields {
static const String MUSEUM_ID = 'id';
static const String MUSEUM_NAME = 'name';
static const String SESSION_TIME = 'session_time';
static const String MUSEUM_DIST_ID = 'distId';
static const String MUSEUM_PHOTO = 'photo';
static const String MUSEUM_ADDRESS = 'address';
static const String LAT = 'lat';
static const String LONG = 'long';
static const String MUSEUM_SECTION_ID = 'sectionId';
static const String EMAIL = 'email';
static const String UPDATED_AT = 'updated_at';
static const String CREATED_AT = 'created_at';
}
class MuseumsList {
List<Data>? data;
MuseumsList({this.data});
MuseumsList.fromJson(Map<String, dynamic> json) {
if (json['data'] != null) {
data = <Data>[];
json['data'].forEach((v) {
data!.add(new Data.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
print("TOJSON");
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.data != null) {
data['data'] = this.data!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Data {
int? id;
String? name;
int? sessionTime;
String? distId;
String? photo;
String? address;
String? lat;
String? long;
String? sectionId;
String? email;
DateTime? updatedAt;
DateTime? createdAt;
Data({
this.id,
this.name,
this.sessionTime,
this.distId,
this.photo,
this.address,
this.lat,
this.long,
this.sectionId,
this.email,
this.updatedAt,
this.createdAt,
});
Data.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
sessionTime = json['session_time'];
distId = json['distId'];
photo = json['photo'];
address = json['address'];
lat = json['lat'];
long = json['long'];
sectionId = json['sectionId'];
email = json['email'];
updatedAt = DateTime.parse(json["updated_at"]);
createdAt = DateTime.parse(json["created_at"]);
}
Map<String, Object?> toJson() => {
MuseumsFields.MUSEUM_ID: id,
MuseumsFields.MUSEUM_NAME: name,
MuseumsFields.SESSION_TIME: sessionTime,
MuseumsFields.MUSEUM_DIST_ID: distId,
MuseumsFields.MUSEUM_PHOTO: photo,
MuseumsFields.MUSEUM_ADDRESS: address,
MuseumsFields.LAT: lat,
MuseumsFields.LONG: long,
MuseumsFields.MUSEUM_SECTION_ID: sectionId,
MuseumsFields.EMAIL: email,
MuseumsFields.UPDATED_AT: updatedAt!.toIso8601String(),
MuseumsFields.CREATED_AT: createdAt!.toIso8601String(),
};
}
database provider file:
import 'dart:io';
import 'package:path/path.dart';
import 'package:the_vom/models/museums_list_model.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
class DBProvider {
static final DBProvider instance = DBProvider._init();
static Database? _database;
DBProvider._init();
Future<Database?> get database async {
if (_database != null) return _database!;
_database = await _initDB('museums.db');
return _database;
}
Future<Database> _initDB(String filePath) async {
// final dbPath = await getDatabasesPath();
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, filePath);
print('database location: $path');
return await openDatabase(path, version: 1, onCreate: _createDB);
}
Future _createDB(Database db, int version) async {
final idType = 'INTEGER PRIMARY KEY';
final textType = 'TEXT';
final intType = 'INTEGER';
await db.execute('''
CREATE TABLE $tableMuseums (
${MuseumsFields.MUSEUM_ID} $idType,
${MuseumsFields.MUSEUM_NAME} $textType,
${MuseumsFields.SESSION_TIME} $intType,
${MuseumsFields.MUSEUM_DIST_ID} $textType,
${MuseumsFields.MUSEUM_PHOTO} $textType,
${MuseumsFields.MUSEUM_ADDRESS} $textType,
${MuseumsFields.LAT} $textType,
${MuseumsFields.LONG} $textType,
${MuseumsFields.MUSEUM_SECTION_ID} $textType,
${MuseumsFields.EMAIL} $textType,
${MuseumsFields.UPDATED_AT} $textType,
${MuseumsFields.CREATED_AT} $textType
)
''');
print("database table is created.");
}
Future<MuseumsList> create(MuseumsList museum) async {
print("inside of create function in db_provider.dart");
final db = await instance.database;
final json = museum.toJson();
print("+++++++++++");
print(json.values);
print("+++++++++++");
// // COLUMN NAMES
// final columns =
// '${MuseumsFields.MUSEUM_ID}, ${MuseumsFields.MUSEUM_NAME}, ${MuseumsFields.SESSION_TIME}, ${MuseumsFields.MUSEUM_DIST_ID}, ${MuseumsFields.MUSEUM_PHOTO}, ${MuseumsFields.MUSEUM_ADDRESS}, ${MuseumsFields.LAT}, ${MuseumsFields.LONG}, ${MuseumsFields.MUSEUM_SECTION_ID}, ${MuseumsFields.EMAIL}, ${MuseumsFields.UPDATED_AT}, ${MuseumsFields.CREATED_AT}';
// // ROWS
// final values =
// '${json[MuseumsFields.MUSEUM_ID]}, ${json[MuseumsFields.MUSEUM_NAME]}, ${json[MuseumsFields.SESSION_TIME]}, ${json[MuseumsFields.MUSEUM_DIST_ID]}, ${json[MuseumsFields.MUSEUM_PHOTO]}, ${json[MuseumsFields.MUSEUM_ADDRESS]}, ${json[MuseumsFields.LAT]}, ${json[MuseumsFields.LONG]}, ${json[MuseumsFields.MUSEUM_SECTION_ID]}, ${json[MuseumsFields.EMAIL]}, ${json[MuseumsFields.UPDATED_AT]}, ${json[MuseumsFields.CREATED_AT]}';
//
// final y = await db!
// .rawInsert('INSERT INTO $tableMuseums ($columns) VALUES ($values)');
final x =
await db!.insert(tableMuseums, museum.toJson()); //convert to a map.
print("museums are saved in the database.");
return museum;
}
Future close() async {
final db = await instance.database;
db!.close();
}
}
service file: I pass my decoded response.body to db provider here as you can see below.
class MuseumsService {
Future getMuseums() async {
print("Future getMuseums");
try {
// headers of the post request
final _headers = {
//todo bearer token, remove the hardcoded one.
'Authorization': _hardCodedBearerToken,
'Content-Type': 'application/x-www-form-urlencoded',
};
// body of the post request
// final _body = '';
// sending post request
http.Response response = await http.post(
loginAPIURL,
headers: _headers,
// body: _body,
);
print("getMuseums Request Sent!");
//get response from endpoint
if (response.statusCode == 200) {
print('$loginAPIURL Endpoint Response: response.body');
print(response.body);
MuseumsList museums =
await MuseumsList.fromJson(jsonDecode(response.body));
// print(museums.data![0].name);
DBProvider.instance.create(museums); //-> ****
}
} catch (e) {
print(e);
return throw Exception("MUSEUMSLIST ALINAMADI");
}
}
}
You are trying to insert the result of MuseumsList.toJson instead of Data.toJson
Try with something like this:
Future<MuseumsList> create(MuseumsList museums) async {
print("inside of create function in db_provider.dart");
final db = await instance.database;
// {'data': [...]}
final jsons = museums.toJson();
if (jsons['data'] != null) {
batch = db!.batch();
jsons['data'].forEach((museum) {
batch.insert(tableMuseums, museum);
});
await batch.commit();
}
print("museums are saved in the database.");
return museums;
}
I created an item in dynamodb using Node js, the item has multiple attributes such as brand, category, discount, validity, etc. I am using uuid to generate ids for each item. Now let's say I want to update the validity attribute of the item, in which case I am currently sending the entire json object with the value of validity modified to the new value.
This is definitely not optimal, please help me find an optimal solution.
const params = {
TableName: process.env.PRODUCT_TABLE,
Key: {
id: event.pathParameters.id,
},
ExpressionAttributeNames: {
'#discount': 'discount',
},
ExpressionAttributeValues: {
':brand': data.brand,
':category': data.category,
':discount': data.discount,
':denominations': data.denominations,
":validity": data.validity,
":redemption": data.redemption
},
UpdateExpression: 'SET #discount = :discount, denominations = :denominations, brand = :brand, category = :category, validity = :validity, redemption = :redemption',
ReturnValues: 'ALL_NEW',
};
I want to send just the attribute I want to update with the new value, if I want to change the validity from 6 months to 8 months, I should just send something like:
{
"validity": "8 months"
}
And it should update the validity attribute of the item.
Same should apply to any other attribute of the item.
'use strict';
const AWS = require('aws-sdk');
const dynamoDb = new AWS.DynamoDB.DocumentClient();
module.exports.update = (event, context, callback) => {
const data = JSON.parse(event.body);
let attr = {};
let nameobj = {};
let exp = 'SET #';
let arr = Object.keys(data);
let attrname = {};
arr.map((key) => {attr[`:${key}`]=data[key]});
arr.map((key) => {
exp += `${key} = :${key}, `
});
arr.map((key) => {nameobj[`#${key}`]=data[key]});
attrname = {
[Object.keys(nameobj)[0]] : nameobj[Object.keys(nameobj)[0]]
}
const params = {
TableName: process.env.PRODUCT_TABLE,
Key: {
id: event.pathParameters.id,
},
ExpressionAttributeNames: attrname,
ExpressionAttributeValues: attr,
UpdateExpression: exp,
ReturnValues: 'ALL_NEW',
};
// update the todo in the database
dynamoDb.update(params, (error, result) => {
// handle potential errors
if (error) {
console.error(error);
callback(null, {
statusCode: error.statusCode || 501,
headers: { 'Content-Type': 'text/plain' },
body: 'Couldn\'t update the card',
});
return;
}
// create a response
const response = {
statusCode: 200,
body: JSON.stringify(result.Attributes),
};
callback(null, response);
});
};
Contrary to others comments, this is very possible, use the UpdateItem action.
Language agnostic API docs
JavaScript specific API docs
If you want to dynamically create the query, try something like this:
const generateUpdateQuery = (fields) => {
let exp = {
UpdateExpression: 'set',
ExpressionAttributeNames: {},
ExpressionAttributeValues: {}
}
Object.entries(fields).forEach(([key, item]) => {
exp.UpdateExpression += ` #${key} = :${key},`;
exp.ExpressionAttributeNames[`#${key}`] = key;
exp.ExpressionAttributeValues[`:${key}`] = item
})
exp.UpdateExpression = exp.UpdateExpression.slice(0, -1);
return exp
}
let data = {
'field' : { 'subfield': 123 },
'other': '456'
}
let expression = generateUpdateQuery(data)
let params = {
// Key, Table, etc..
...expression
}
console.log(params)
Output:
{
UpdateExpression: 'set #field = :field, #other = :other',
ExpressionAttributeNames: {
'#field': 'field',
'#other': 'other'
},
ExpressionAttributeValues: {
':field': {
'subfield': 123
},
':other': '456'
}
}
Using Javascript SDK V3:
Import from the right package:
import { DynamoDBClient PutItemCommandInput, UpdateItemCommandInput, UpdateItemCommand } from '#aws-sdk/client-dynamodb';
Function to dynamically do partial updates to the item:
(the code below is typescript can be easily converted to Javascript, just remove the types!)
function updateItem(id: string, item: any) {
const dbClient = new DynamoDBClient({region: 'your-region-here });
let exp = 'set ';
let attNames: any = { };
let attVal: any = { };
for(const attribute in item) {
const valKey = `:${attribute}`;
attNames[`#${attribute}`] = attribute;
exp += `#${attribute} = ${valKey}, `;
const val = item[attribute];
attVal[valKey] = { [getDynamoType(val)]: val };
}
exp = exp.substring(0, exp.length - 2);
const params: UpdateItemCommandInput = {
TableName: 'your-table-name-here',
Key: { id: { S: id } },
UpdateExpression: exp,
ExpressionAttributeValues: attVal,
ExpressionAttributeNames: attNames,
ReturnValues: 'ALL_NEW',
};
try {
console.debug('writing to db: ', params);
const command = new UpdateItemCommand(params);
const res = await dbClient.send(command);
console.debug('db res: ', res);
return true;
} catch (err) {
console.error('error writing to dynamoDB: ', err);
return false;
}
}
And to use it (we can do partial updates as well):
updateItem('some-unique-id', { name: 'some-attributes' });
What i did is create a helper class.
Here is a simple function : Add all the attribute and values that goes into, if the value is null or undefined it won't be in the expression.
I recommande to create a helper class with typescript and add more functions and other stuff like generator of expressionAttributeValues , expressionAttributeNames ... , Hope this help.
function updateExpression(attributes, values) {
const expression = attributes.reduce((res, attribute, index) => {
if (values[index]) {
res += ` #${attribute}=:${attribute},`;
}
return res;
}, "SET ");
return expression.slice(0, expression.length - 1)
}
console.log(
updateExpression(["id", "age", "power"], ["e8a8da9a-fab0-55ba-bae3-6392e1ebf624", 28, undefined])
);
You can use code and generate the params object based on the object you provide. It's just a JavaScript object, you walk through the items so that the update expression only contains the fields you have provided.
This is not really a DynamoDB question in that this is more a general JS coding question.
You can use UpdateItem; to familiarize yourself with DynamoDb queries I would suggest you DynamoDb NoSQL workbench:
https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.settingup.html
It can generate snippets for you based on your queries.
DynamoDb NoSQL workbench screenshot query
I'm trying to validate my data against a SimpleSchema before it gets submitted to the collection but for some reason I'm not able to do so with this error.
Exception while invoking method 'createVendorCategory' { stack: 'TypeError: Cannot call method \'simpleSchema\' of undefined
I have one collections with two SimpleSchemas as follows.
Vendors = new Mongo.Collection('vendors'); //Define the collection.
VendorCategoriesSchema = new SimpleSchema({
name: {
type: String,
label: "Category"
},
slug: {
type: String,
label: "Slug"
},
createdAt : {
type: Date,
label: "Created At",
autoValue: function(){
return new Date()//return the current date timestamp to the schema
}
}
});
VendorSchema = new SimpleSchema({
name: {
type: String,
label: "Name"
},
phone: {
type: String,
label: "Phone"
},
vendorCategories:{
type: [VendorCategoriesSchema],
optional: true
}
});
Vendors.attachSchema(VendorSchema);
The vendorCategory will be added after the Vendor document is created by the user.
Here is what my client side looks like.
Template.addCategory.events({
'click #app-vendor-category-submit': function(e,t){
var category = {
vendorID: Session.get("currentViewingVendor"),
name: $.trim(t.find('#app-cat-name').value),
slug: $.trim(t.find('#app-cat-slug').value),
};
Meteor.call('createVendorCategory', category, function(error) {
//Server-side validation
if (error) {
alert(error);
}
});
}
});
And here is what my server side Meteor.methods look like
createVendorCategory: function(category)
{
var vendorID = Vendors.findOne(category.vendorID);
if(!vendorID){
throw new Meteor.Error(403, 'This Vendor is not found!');
}
//build the arr to be passed to collection
var vendorCategories = {
name: category.name,
slug: category.slug
}
var isValid = check( vendorCategories, VendorSchema.vendorCategories.simpleSchema());//This is not working?
if(isValid){
Vendors.update(VendorID, vendorCategories);
// return vendorReview;
console.log(vendorCategories);
}
else{
throw new Meteor.Error(403, 'Data is not valid');
}
}
I'm guessing this is where the error is coming from.
var isValid = check( vendorCategories, VendorSchema.vendorCategories.simpleSchema());//This is not working?
Any help would be greatly appreciated.
Since you've already defined a sub-schema for the sub-object you can directly check against that:
check(vendorCategories,VendorCategoriesSchema)