How to Marshall a composite key for GetCommand - amazon-dynamodb

I have a dynamo table with a partition key of 'shop' and sort key 'item'. I want to use GetItemCommand to find a particular item using this composite key.
const params = {
TableName: process.env.DYNAMODB_TABLE_NAME,
Key: marshall({shop: String(event.pathParameters.shop),
item: String(event.pathParameters.item) }),
};
const {Item} = await db.send(new GetItemCommand(params));
console.log("item" + Item);
but it returns undefined

Give this a go
const keys = marshall(
{
shop:event.pathParameters.shop,
item:event.pathParameters.item
})
const params = {
TableName: process.env.DYNAMODB_TABLE_NAME,
Key: keys,
};
console.log(params);
try{
const {Item} = await db.send(new GetItemCommand(params));
console.log("item" + Item);
}catch(e){
console.log(e);
}

Related

Displaying data from SWAPI

I am trying to display film details from this API https://swapi.dev/api/films in NextJS but I keep getting an error. It has something to do with the getStaticPath function. I am using this code: any help welcome.
import fetch from 'isomorphic-unfetch';
export const getStaticPaths = async () => {
const res = await fetch('https://swapi.dev/api/films');
const data = await res.json();
console.log("This is " + JSON.stringify(data));
const paths = data.results.map(film => {
return {
params: { id: film.episode_id.toString() },
};
});
return {
paths,
fallback: false,
};
};
export const getStaticProps = async (context) => {
const id = context.params.id;
const res = await fetch(`https://swapi.dev/api/films` + id);
const data = await res.json();
return {
props: { film: data },
};
};
const Details = ({ film }) => {
return (
<div>
<h1>Episode {film.episode_id}</h1>
<h1>{film.title}</h1>
</div>
);
};
export default Details;
I am expecting the episode ID and title to display
enter image description here
I have tried taking 'results' out of 'data.results.map', so 'data.map' but just results in a error says data.map is not a function...I guess because data is an object not an array. But results is an array so I am still lost. I do think the issue lies here somewhere though...

How to dynamically build query for firestore [duplicate]

For example I have dynamic filter for my list of books where I can set specific color, authors and categories.
This filter can set multiple colors at once and multiple categories.
Book > Red, Blue > Adventure, Detective.
How can I add "where" conditionally?
firebase
.firestore()
.collection("book")
.where("category", "==", )
.where("color", "==", )
.where("author", "==", )
.orderBy("date")
.get()
.then(querySnapshot => {...
As you can see in the API docs, the collection() method returns a CollectionReference. CollectionReference extends Query, and Query objects are immutable. Query.where() and Query.orderBy() return new Query objects that add operations on top of the original Query (which remains unmodified). You will have to write code to remember these new Query objects so you can continue to chain calls with them. So, you can rewrite your code like this:
var query = firebase.firestore().collection("book")
query = query.where(...)
query = query.where(...)
query = query.where(...)
query = query.orderBy(...)
query.get().then(...)
Now you can put in conditionals to figure out which filters you want to apply at each stage. Just reassign query with each newly added filter.
if (some_condition) {
query = query.where(...)
}
Firebase Version 9
The docs do not cover this but here is how to add conditional where clauses to a query
import { collection, query, where } from 'firebase/firestore'
const queryConstraints = []
if (group != null) queryConstraints.push(where('group', '==', group))
if (pro != null) queryConstraints.push(where('pro', '==', pro))
const q = query(collection(db, 'videos'), ...queryConstraints)
The source of this answer is a bit of intuitive guesswork and help from my best friend J-E^S^-U-S
With Firebase Version 9 (Jan, 2022 Update):
You can filter data with multiple where clauses:
import { query, collection, where, getDocs } from "firebase/firestore";
const q = query(
collection(db, "products"),
where("category", "==", "Computer"),
where("types", "array-contains", ['Laptop', 'Lenovo', 'Intel']),
where("price", "<=", 1000),
);
const docsSnap = await getDocs(q);
docsSnap.forEach((doc) => {
console.log(doc.data());
});
In addition to #Doug Stevenson answer. When you have more than one where it is necessary to make it more dynamic as in my case.
function readDocuments(collection, options = {}) {
let {where, orderBy, limit} = options;
let query = firebase.firestore().collection(collection);
if (where) {
if (where[0] instanceof Array) {
// It's an array of array
for (let w of where) {
query = query.where(...w);
}
} else {
query = query.where(...where);
}
}
if (orderBy) {
query = query.orderBy(...orderBy);
}
if (limit) {
query = query.limit(limit);
}
return query
.get()
.then()
.catch()
}
// Usage
// Multiple where
let options = {where: [["category", "==", "someCategory"], ["color", "==", "red"], ["author", "==", "Sam"]], orderBy: ["date", "desc"]};
//OR
// A single where
let options = {where: ["category", "==", "someCategory"]};
let documents = readDocuments("books", options);
Note that a multiple WHERE clause is inherently an AND operation.
If you're using angular fire, you can just use reduce like so:
const students = [studentID, studentID2,...];
this.afs.collection('classes',
(ref: any) => students.reduce(
(r: any, student: any) => r.where(`students.${student}`, '==', true)
, ref)
).valueChanges({ idField: 'id' });
This is an example of multiple tags...
You could easily change this for any non-angular framework.
For OR queries (which can't be done with multiple where clauses), see here.
For example, there's an array look like this
const conditionList = [
{
key: 'anyField',
operator: '==',
value: 'any value',
},
{
key: 'anyField',
operator: '>',
value: 'any value',
},
{
key: 'anyField',
operator: '<',
value: 'any value',
},
{
key: 'anyField',
operator: '==',
value: 'any value',
},
{
key: 'anyField',
operator: '==',
value: 'any value',
},
]
Then you can just put the collection which one you want to set query's conditions into this funcion.
function* multipleWhere(
collection,
conditions = [{ field: '[doc].[field name]', operator: '==', value: '[any value]' }],
) {
const pop = conditions.pop()
if (pop) {
yield* multipleWhere(
collection.where(pop.key, pop.operator, pop.value),
conditions,
)
}
yield collection
}
You will get the collection set query's conditions.
async yourFunction(){
const Ref0 = firebase.firestore().collection("your_collection").doc(doc.id)
const Ref1 = appointmentsRef.where('val1', '==',condition1).get();
const Ref2 = appointmentsRef.where("val2", "!=", condition2).get()
const [snapshot_val1, snapshot_val2] = await Promise.all([Ref1, Ref2]);
const val1_Array = snapshot_val1.docs;
const val2_Array = snapshot_val2.docs;
const globale_val_Array = val1_Array .concat(val2_Array );
return globale_val_Array ;
}
/*Call you function*/
this.checkCurrentAppointment().then(docSnapshot=> {
docSnapshot.forEach(doc=> {
console.log("Your data with multiple code query:", doc.data());
});
});
As CollectionRef does not have query method in firebase web version 9,
I modified #abk's answer.
async getQueryResult(path, options = {}) {
/* Example
options = {
where: [
["isPublic", "==", true],
["isDeleted", "==", false]
],
orderBy: [
["likes"],
["title", "desc"]
],
limit: 30
}
*/
try {
let { where, orderBy, limit } = options;
let collectionRef = collection(<firestore>, path);
let queryConstraints = [];
if (where) {
where = where.map((w) => firestore.where(...w));
queryConstraints = [...queryConstraints, ...where];
}
if (orderBy) {
orderBy = orderBy.map((o) => firestore.orderBy(...o));
queryConstraints = [...queryConstraints, ...orderBy];
}
if (limit) {
limit = firestore.limit(limit);
queryConstraints = [...queryConstraints, limit];
}
const query = firestore.query(collectionRef, ...queryConstraints);
const querySnapshot = await firestore.getDocs(query);
const docList = querySnapshot.docs.map((doc) => {
const data = doc.data();
return {
id: doc.id,
...data,
};
});
return docList;
} catch (error) {
console.log(error);
}
}
Simple function where you can specify the path and an array of filters that you can pass and get you documents, hope it helps.
async function filterDoc(path, filters) {
if (!path) return [];
//define the collection path
let q = db.collection(path);
//check if there are any filters and add them to the query
if (filters.length > 0) {
filters.forEach((filter) => {
q = q.where(filter.field, filter.operator, filter.value);
});
}
//get the documents
const snapshot = await q.get();
//loop through the documents
const data = snapshot.docs.map((doc) => doc.data());
//return the data
return data;
}
//call the function
const data = await filterDoc(
"categories_collection",
[
{
field: "status",
operator: "==",
value: "active",
},
{
field: "parent_id",
operator: "==",
value: "kSKpUc3xnKjtpyx8cMJC",
},
]
);

Use one filfilled for several createAsyncThunk functions

I have two createAsyncThunk - signIn and signUp is it possible to use one fulfilled reducer both? The reason is that fulfilled reducer same for signIn and signUp. Example:
extraReducers: (builder) => {
builder.addCase(signInUser.fulfilled, (state, { payload }) => {
state.isPending = false;
state.email = payload.username;
state.username = payload.username;
state.first_name = payload.first_name;
state.last_name = payload.last_name;
state.title = payload.title;
state.organization = payload.organization;
state.isNew = payload.isNew;
state.isPremium = payload.isPremium;
state.id = payload.id;
state.error = '';
state.access_token = payload.access_token;
localStorage.setItem(REFRESH_TOKEN, payload.refresh_token);
});
}
Yes, have utils for this purpose: watch this
There is an obvious solution that I found after refactoring, you can pass state and payload to another function and it can set state as it would in yourAsyncThunk.fulfilled. Example:
builder.addCase(signInUser.fulfilled, (state, { payload }) => {
assignStateWithUser(state, payload);
});
builder.addCase(signUpUser.fulfilled, (state, { payload }) => {
assignStateWithUser(state, payload);
});
builder.addCase(loadUser.fulfilled, (state, { payload }) => {
assignStateWithUser(state, payload);
});
const assignStateWithUser = (state: initialStateUser, payload: User) => {
state.email = payload.username;
state.username = payload.username;
state.first_name = payload.first_name;
state.last_name = payload.last_name;
state.title = payload.title;
state.organization = payload.organization;
};
Types for state and payload:
type initialStateUser = RequestPending & { error: string } & User;
export interface User {
id: number;
username: string;
first_name: string;
last_name: string;
email: string;
title: string;
organization: string;
};

How to programmatically form a firestore query? [duplicate]

For example I have dynamic filter for my list of books where I can set specific color, authors and categories.
This filter can set multiple colors at once and multiple categories.
Book > Red, Blue > Adventure, Detective.
How can I add "where" conditionally?
firebase
.firestore()
.collection("book")
.where("category", "==", )
.where("color", "==", )
.where("author", "==", )
.orderBy("date")
.get()
.then(querySnapshot => {...
As you can see in the API docs, the collection() method returns a CollectionReference. CollectionReference extends Query, and Query objects are immutable. Query.where() and Query.orderBy() return new Query objects that add operations on top of the original Query (which remains unmodified). You will have to write code to remember these new Query objects so you can continue to chain calls with them. So, you can rewrite your code like this:
var query = firebase.firestore().collection("book")
query = query.where(...)
query = query.where(...)
query = query.where(...)
query = query.orderBy(...)
query.get().then(...)
Now you can put in conditionals to figure out which filters you want to apply at each stage. Just reassign query with each newly added filter.
if (some_condition) {
query = query.where(...)
}
Firebase Version 9
The docs do not cover this but here is how to add conditional where clauses to a query
import { collection, query, where } from 'firebase/firestore'
const queryConstraints = []
if (group != null) queryConstraints.push(where('group', '==', group))
if (pro != null) queryConstraints.push(where('pro', '==', pro))
const q = query(collection(db, 'videos'), ...queryConstraints)
The source of this answer is a bit of intuitive guesswork and help from my best friend J-E^S^-U-S
With Firebase Version 9 (Jan, 2022 Update):
You can filter data with multiple where clauses:
import { query, collection, where, getDocs } from "firebase/firestore";
const q = query(
collection(db, "products"),
where("category", "==", "Computer"),
where("types", "array-contains", ['Laptop', 'Lenovo', 'Intel']),
where("price", "<=", 1000),
);
const docsSnap = await getDocs(q);
docsSnap.forEach((doc) => {
console.log(doc.data());
});
In addition to #Doug Stevenson answer. When you have more than one where it is necessary to make it more dynamic as in my case.
function readDocuments(collection, options = {}) {
let {where, orderBy, limit} = options;
let query = firebase.firestore().collection(collection);
if (where) {
if (where[0] instanceof Array) {
// It's an array of array
for (let w of where) {
query = query.where(...w);
}
} else {
query = query.where(...where);
}
}
if (orderBy) {
query = query.orderBy(...orderBy);
}
if (limit) {
query = query.limit(limit);
}
return query
.get()
.then()
.catch()
}
// Usage
// Multiple where
let options = {where: [["category", "==", "someCategory"], ["color", "==", "red"], ["author", "==", "Sam"]], orderBy: ["date", "desc"]};
//OR
// A single where
let options = {where: ["category", "==", "someCategory"]};
let documents = readDocuments("books", options);
Note that a multiple WHERE clause is inherently an AND operation.
If you're using angular fire, you can just use reduce like so:
const students = [studentID, studentID2,...];
this.afs.collection('classes',
(ref: any) => students.reduce(
(r: any, student: any) => r.where(`students.${student}`, '==', true)
, ref)
).valueChanges({ idField: 'id' });
This is an example of multiple tags...
You could easily change this for any non-angular framework.
For OR queries (which can't be done with multiple where clauses), see here.
For example, there's an array look like this
const conditionList = [
{
key: 'anyField',
operator: '==',
value: 'any value',
},
{
key: 'anyField',
operator: '>',
value: 'any value',
},
{
key: 'anyField',
operator: '<',
value: 'any value',
},
{
key: 'anyField',
operator: '==',
value: 'any value',
},
{
key: 'anyField',
operator: '==',
value: 'any value',
},
]
Then you can just put the collection which one you want to set query's conditions into this funcion.
function* multipleWhere(
collection,
conditions = [{ field: '[doc].[field name]', operator: '==', value: '[any value]' }],
) {
const pop = conditions.pop()
if (pop) {
yield* multipleWhere(
collection.where(pop.key, pop.operator, pop.value),
conditions,
)
}
yield collection
}
You will get the collection set query's conditions.
async yourFunction(){
const Ref0 = firebase.firestore().collection("your_collection").doc(doc.id)
const Ref1 = appointmentsRef.where('val1', '==',condition1).get();
const Ref2 = appointmentsRef.where("val2", "!=", condition2).get()
const [snapshot_val1, snapshot_val2] = await Promise.all([Ref1, Ref2]);
const val1_Array = snapshot_val1.docs;
const val2_Array = snapshot_val2.docs;
const globale_val_Array = val1_Array .concat(val2_Array );
return globale_val_Array ;
}
/*Call you function*/
this.checkCurrentAppointment().then(docSnapshot=> {
docSnapshot.forEach(doc=> {
console.log("Your data with multiple code query:", doc.data());
});
});
As CollectionRef does not have query method in firebase web version 9,
I modified #abk's answer.
async getQueryResult(path, options = {}) {
/* Example
options = {
where: [
["isPublic", "==", true],
["isDeleted", "==", false]
],
orderBy: [
["likes"],
["title", "desc"]
],
limit: 30
}
*/
try {
let { where, orderBy, limit } = options;
let collectionRef = collection(<firestore>, path);
let queryConstraints = [];
if (where) {
where = where.map((w) => firestore.where(...w));
queryConstraints = [...queryConstraints, ...where];
}
if (orderBy) {
orderBy = orderBy.map((o) => firestore.orderBy(...o));
queryConstraints = [...queryConstraints, ...orderBy];
}
if (limit) {
limit = firestore.limit(limit);
queryConstraints = [...queryConstraints, limit];
}
const query = firestore.query(collectionRef, ...queryConstraints);
const querySnapshot = await firestore.getDocs(query);
const docList = querySnapshot.docs.map((doc) => {
const data = doc.data();
return {
id: doc.id,
...data,
};
});
return docList;
} catch (error) {
console.log(error);
}
}
Simple function where you can specify the path and an array of filters that you can pass and get you documents, hope it helps.
async function filterDoc(path, filters) {
if (!path) return [];
//define the collection path
let q = db.collection(path);
//check if there are any filters and add them to the query
if (filters.length > 0) {
filters.forEach((filter) => {
q = q.where(filter.field, filter.operator, filter.value);
});
}
//get the documents
const snapshot = await q.get();
//loop through the documents
const data = snapshot.docs.map((doc) => doc.data());
//return the data
return data;
}
//call the function
const data = await filterDoc(
"categories_collection",
[
{
field: "status",
operator: "==",
value: "active",
},
{
field: "parent_id",
operator: "==",
value: "kSKpUc3xnKjtpyx8cMJC",
},
]
);

Passing variables between functions on the same screen

Here you can see the variable called ChatID.
getChatId() {
const IDloc = firebase.database().ref('/rooms');
const newChat = IDloc.push({
title: 'New chat over again'
});
const ChatID = newChat.key;
try {
AsyncStorage.getItem('email').then((email) => {
const membersList = firebase.database().ref('/members').child(ChatID);
const user1 = email
console.log('user1: ', user1);
const user = firebase.auth().currentUser;
membersList.set({
user1: user1,
user2: user.email
});
}).done();
} catch (error) {
console.log('Error has accurated');
}
}
get ref() {
return firebase.database().ref('/messages').child(this.getChatId.ChatID);
}
What I need to do is to pass this variable from getChatId() to ref() and insert this ChatID inside of child.
When I do this the way I did in my code I get undefined instead of ChatID. When I try to do this with state={}, then I just get null.
How can I fix it?
If you are using a class you can do the following
ChatID = '' //declare the variable outside
getChatId() {
const IDloc = firebase.database().ref('/rooms');
const newChat = IDloc.push({
title: 'New chat over again'
});
this.ChatID = newChat.key; //set the variable
try {
AsyncStorage.getItem('email').then((email) => {
const membersList = firebase.database().ref('/members').child(ChatID);
const user1 = email
console.log('user1: ', user1);
const user = firebase.auth().currentUser;
membersList.set({
user1: user1,
user2: user.email
});
}).done();
} catch (error) {
console.log('Error has accurated');
}
}
get ref() {
return firebase.database().ref('/messages').child(this.ChatID);
}

Resources