How do I get nested reference data in firestore? - firebase

I'm trying to get data by dates and render html in firestore,
But I cannot that.
The order is wrong.
Because, The data is sorted by user.
How do I get data by date?
{
comments: {
comment_1: {
userRef: users/user_1,
body: "body",
createdAt: Timestamp,
},
comment_2: {
userRef: users/user_2,
body: "body",
createdAt: Timestamp,
},
comment_3: {
userRef: users/user_1,
body: "body",
createdAt: Timestamp,
},
},
users: {
user_1 : {
name: "test"
},
user_2 : {
name: "test"
},
}
}
db.collection('comments').orderBy('createdAt').get().then(snapshot=> {
const comment = snapshot.data();
comment.userRef.get().then(userSnapshot => {
const userData = userSnapshot.data();
const comment = document.getElementById('js-comment');
const element = document.createElement('div')
element.innerHTML = `<p>${comment.body}</p>`
comment.appendChild(element);
});
});

You need to sort the data using orderBy the date field as you have in the code, however, you do not have a field createdAt in the data model you have provided.
If your comments data looks like this
comments: {
comment_1: {
userRef: users/user_1,
body: "body",
createdAt: Timestamp
},
comment_2: {
userRef: users/user_2,
body: "body",
createdAt: Timestamp
},
comment_3: {
userRef: users/user_1,
body: "body",
createdAt: Timestamp
},
The timestamp field can be filled in by getting firestore to fill the field using Timestamp.now() when the data is created.
Once the data is read using the orderBy for the comments. You need to specify ASCENDING if you want the data to be increasing order, then the users can be looked up and the data should appear in the correct order.
This is discussed more here https://firebase.google.com/docs/firestore/query-data/order-limit-data

Related

Why is dynamodb.update() is not updating the field in my Table?

I have a dynamodb Table named "user_subscription", I want to update the status field from "ACTIVE" to "INACTIVE",
const params = {
TableName: "user_subscription",
Key: {
userId: userId,
subscription_id: "abc",
},
updateExpression: "SET status = :newStatus",
expressionAttributeValues: { ":newStatus": "INACTIVE" },
ReturnValues: "ALL_NEW",
};
console.log("params", params);
try {
dynamoDb.update(params, (error, data) => {
console.log("error", error, "data", data);
});
} catch (err) {}
This code doesn't update the status field.
The response data which I get is:
Attributes: {
plan_id: 'dkdkkd',
subscription_id: 'abc',
userId: 'ebef4c92-9fa8-4e1b-878f-d5753bb4042a',
updatedAt: '2022-12-25T08:18:32.681Z',
status: 'ACTIVE',
createdAt: '2022-12-25T08:18:32.681Z'
}
Status is a reserved keyword in DynamoDB, I believe the code you shared should be throwing several errors, are you sure you are executing the correct code while testing?
To fix your errors, try these params:
const params = {
TableName: "user_subscription",
Key: {
userId: userId,
subscription_id: "abc",
},
UpdateExpression: "SET #status = :newStatus",
ExpressionAttributeValues: { ":newStatus": "INACTIVE" },
ExpressionAttributeNamee: { "#status": "status" },
ReturnValues: "ALL_NEW",
};

DynamoDB result is not structured the way I want

I am doing a simple command to list all the items in my table. However, the data I am getting back is not structured the way I want. I want a simple JSON structure but DynamoDB is turning the results into nested objects.
DynamoDB gives me below response:
// What I am currently getting
[
{
id: { S: '8' },
lastName: { S: 'Perry' },
firstName: { S: 'Matthew' }
},
{
id: { S: '3' },
firstName: { S: 'Joan' },
lastName: { S: 'Peter' }
}
]
But I want this:
// What I want
[
{
id: 8
lastName: 'Perry' ,
firstName: 'Matthew'
},
{
id: 3,
firstName: 'Joan' ,
lastName: 'Peter'
}
]
How can I achieve the later result set. Below is my code:
const { ExecuteStatementCommand } = require('#aws-sdk/client-dynamodb')
const { ddbDocClient, memberTableName } = require('./client.js')
const selectAll = async () => {
const params = {
Statement: `SELECT * FROM ${memberTableName}`,
Parameters: [{ S: '3' }]
}
console.log(params)
return await ddbDocClient.send(new ExecuteStatementCommand(params));
}
selectAll()
.then(d => console.log(d.Items))
ddbDocClient was created like this:
const ddbDocClient = DynamoDBDocumentClient.from(ddbClient);
The command import is incorrect. To send and receive native JS types, import the ExecuteStatementCommand command from the #aws-sdk/lib-dynamodb "document client" package.
const { ExecuteStatementCommand } = require('#aws-sdk/lib-dynamodb');
You are importing the command from the "regular client" package #aws-sdk/client-dynamodb, i.e. the one that accepts and returns DynamoDB JSON.
Note: The Parameters: [{ S: '3' }] line is also wrong, but it's currently not causing trouble because your statement is scanning for all records. If you were to include a WHERE id=? phrase in the statement, make sure to change the parameters to Parameters: ['3']. You must pass JS types to the "document client" commands.
You need use simple lib https://www.npmjs.com/package/#aws-sdk/util-dynamodb
then use like this:
const { DynamoDB } = require("#aws-sdk/client-dynamodb");
const { marshall, unmarshall } = require("#aws-sdk/util-dynamodb");
const client = new DynamoDB(clientParams);
const params = {
TableName: "Table",
Key: marshall({
HashKey: "hashKey",
}),
};
const { Item } = await client.getItem(params);
unmarshall(Item);

How to get included model data count in prisma with where clause?

i need to get user details with post count(Number of posts for today).
const usersWithCount = await prisma.user.findMany({
select: {
_count: {
select: {
posts: {
where: {
createdAt: moment().format("YYYY-MM-DD"),
},
},
recipes: true,
},
},
},
})
You cannot filter in relations count, this is not currently supported by prisma.
Here is the Feature Request for adding filters in relations count.
In your use case you can get filtered relations as described below:
const usersWithCount = await prisma.user.findMany({
select: {
posts: {
where: {
createdAt: moment().format("YYYY-MM-DD"),
},
},
recipes: true
},
});
In the response of the above query you will get posts array with records satisfying your where condition, you can use the array's length as a count.

Meteor collections: upsert w/ array

Forms of this question have been asked a few times, but I've been unable to find a solution:
I have a schema like this (simplified):
StatusObject = new SimpleSchema({
statusArray: [statusSchema]
});
where statusSchema is
{
topicId:{
type: String,
optional: true
},
someInfo:{
type: Number,
optional: true,
decimal: true
},
otherInfo:{
type: Number,
optional: true
}
}
I am trying to upsert - with the following meteor method code:
var upsertResult = BasicInfo.update({
userId: this.userId,
statusArray: {
$elemMatch: { topicId : newStatus.topicId }
}
}, {
$set: {
"statusArray.$.topicId": newStatus.topicId,
"statusArray.$.someInfo": newStatus.someInfo,
"statusArray.$.otherInfo": newStatus.otherInfo
}
}, {
multi: true,
upsert: true
});
But I keep getting an error: statusArray must be an array
I thought by adding the $, I was making sure it is recognized as an array? What am I missing?
It seems (after your clarification comments), that you want to find a document with particular userId and modify its statusArray array using one of these scenarios:
Update existing object with particular topicId value;
Add a new object if the array doens't have one with particular topicId value.
Unfortunately, you can't make it work using just one DB query, so it should be like this:
// try to update record
const updateResult = BasicInfo.update({
userId: this.userId,
'statusArray.topicId': newStatus.topicId
}, {
$set: {
"statusArray.$": newStatus
}
});
if (!updateResult) {
// insert new record to array or create new document
BasicInfo.update({
userId: this.userId
}, {
$push: {
statusArray: newStatus
},
$setOnInsert: {
// other needed fields
}
}, {
upsert: true
});
}
Your code is treating StatusArray as an object,
Before you do the upsert, build the status array first, assuming that your current value is currentRecord
newStatusArray = currentRecord.statusArray
newStatusArray.push({
topicId: newStatus.topicId,
someInfo : newStatus.someInfo,
otherInfo: newStatus.otherInfo
})
and in the upsert, simply refer to it like this
$set: { statusArray: newStatusArray}

meteor - How to add a subdocument as reference with SimpleSchema

I have the following SimpleSchema
Schema.Team = new SimpleSchema({
name:{
type:String
},
members: {
type: [Schema.User],
optional:true
}
});
I would like to insert (on the server) a new team document with the current user, as a reference (not as an embedded document).
I have tried:
Teams.insert({name:"theName",members:[Meteor.user()]}) // works but insert the user as an embedded doc.
Teams.insert({name:"theName",members:[Meteor.user()._id]}) // Error: 0 must be an object
I have also tried in two steps:
var id = Teams.insert({name:teamName});
Teams.update({ _id: id },{ $push: { 'users': Meteor.user()._id } });
Then I have another error I don't understand: Error: When the modifier option is true, validation object must have at least one operator
So how can I insert a document with a reference to another schema?
If you just want to store an array of userIds in your Team collection try:
Schema.Team = new SimpleSchema({
name:{
type:String
},
members: {
type: [String],
optional:true
}
});
Then
Teams.insert({ name: "theName", members: [Meteor.userId()] });
Should work. Later when you want to add an additional id you can just:
Teams.update({ _id: teamId },{ $addToSet: { members: Meteor.userId() }});
The following is probably the syntax you are after, assuming you are also using AutoForm.
If you are using collection2, you can also add an autovalue for when a team is created to automatically add the creator to that team for more convenience.
Schema.Team = new SimpleSchema({
name: {
type:String
},
members: {
type: [String],
defaultValue: [],
allowedValues: function () {
// only allow references to the user collection.
return Meteor.users.find().map(function (doc) {
return doc._id
});
},
autoform: {
// if using autoform, this will display their username as the option instead of their id.
options: function () {
return Meteor.users.find().map(function (doc) {
return {
value: doc._id,
label: doc.username // or something
}
})
}
},
autoValue: function () {
if (this.isInsert && !this.isFromTrustedCode) {
return [this.userId];
}
}
}
});

Resources