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

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.

Related

Problems structuring and querying a table properly - DynamoDB

I am new to dynamoDB. I am having difficulty developing a table structure. I have data that can best be thought of as a folder structure. There are folders which are nested in parent folders. Most of the time, I will be querying for all folders with a given parent folder, however, there are times when I will be querying individual folders.
If I use the parent_id (parent folder) as the partition key and the id of the individual folder as the sort key, I believe that this creates a table where all related files are stored together and I can query them efficiently. However, I have questions.
First, the query "works" in that it returns the data, but is it written so that it queries the data correctly and is not merely scrolling through the whole table?
router.get("/api/children_folders/:parent_id", (req, res, next) => {
let parent_id = req.params.parent_id;
let params = {
TableName: tableName,
KeyConditionExpression: "parent_id = :pid",
ExpressionAttributeValues: {
":pid": parent_id,
},
ScanIndexForward: false,
};
docClient.query(params, (err, data) => {
if (err) {
console.log(err);
return res.status(err.statusCode).send({
message: err.message,
status: err.statusCode,
});
} else {
return res.status(200).send(data);
}
});
});
Second, if I want to query for individual tags, do I need to pass in a combination of the parent folder ID and the actual ID, or is this OK?
router.get("/api/folder/:folder_id", (req, res, next) => {
let tag_id = req.params.folder_id;
let params = {
TableName: tableName,
KeyConditionExpression: "folder_id = :fid",
ExpressionAttributeValues: {
":fid": folder_id,
},
Limit: 1,
};
docClient.query(params, (err, data) => {
if (err) {
console.log(err);
return res.status(err.statusCode).send({
message: err.message,
status: err.statusCode,
});
} else {
if (!_.isEmpty(data.Items)) {
return res.status(200).send(data.Items[0]);
} else {
return res.status(404).send();
}
}
});
});
I just feel like I am missing some thing here and I want to make sure that I am grabbing the data correctly.
The PK, should be something that would divide the load equally (ideally). I don't the fully picture of your problem but assuming you can chose a good parent folder as a partition key, then you can insert every file/dir with a sort key representing its full path
For example:
PK SK
/home /username/pictures/cat.jpg
This way if you want to get a specific item you can use the get item request
var params = {
Key: {
"PK": { "S": "/home" },
"SK": { "S": "/username/pictures/cat.jpg" }
},
TableName: tableName
};
var result = await dynamodb.getItem(params).promise()
Now if you want to list all the files in "/home/username/pictures" you can use begins with query
const params = {
TableName: 'tablenName',
KeyConditionExpression: '#PK = :root_path and begins_with(#SK, :sub_path)',
ExpressionAttributeNames:{
"#user_id": "root_path",
"#user_relation": 'sub_path'
},
ExpressionAttributeValues: {
":root_path": "/home",
":sub_path": "/username/pictures"
}
}

How to Publish joined Data from Array of IDs in Meteor

I just want to Publish the relational Data for a Publication to client, but the issue is my Relational Data field is array of ID's of a Different Collection, I tried Different Packages but all works with single Relational ID but not working with Array of relational ID's, let assume I have two Collection Companies and Meteor.users below is my Company Document Looks like
{
_id : "dYo4tqpZms9j8aG4C"
owner : "yjzakAgYWejmJcuHz"
name : "Labbaik Waters"
peoples : ["yjzakAgYWejmJcuHz", "yjzakAgYWejmJcuHz"],
createdAt: "2019-09-18T15:33:29.952+00:00"
}
here you can see peoples field contains the user ID's as Array, so How I publish this userId's as user Documents, as for example I tried the most popular meteor package named publishComposit, when I tried Loop in Children's find, I got undefined in children i.e below
publishComposite('compoundCompanies', {
find() {
// Find top ten highest scoring posts
return Companies.find({
owner: this.userId
}, {sort: {}});
},
children: [
{
find(company) {
let cursors = company.peoples.forEach(peopleId => {
console.log(peopleId)
return Meteor.users.find(
{ _id: peopleId },
{ fields: { profile: 1 } });
})
//here cursor undefined
console.log(cursors)
return cursors
}
}
]
});
and if I implement async loop in children's find I got error like below code
publishComposite('compoundCompanies', {
find() {
// Find top ten highest scoring posts
return Companies.find({
owner: this.userId
}, {sort: {}});
},
children: [
{
async find(company) {
let cursors = await company.peoples.forEach(peopleId => {
console.log(peopleId)
return Meteor.users.find(
{ _id: peopleId },
{ fields: { profile: 1 } });
})
//here cursor undefined
console.log(cursors)
return cursors
}
}
]
});
the error occured in above code is Exception in callback of async function: TypeError: this.cursor._getCollectionName is not a function
I don't know what I am exactly doing wrong here, or implementing package function not as intended any help will be greatly appropriated
EDIT: my desired result should be full user documents instead of ID no matter it mapped in same peoples array or as another fields I just want as below
{
_id: "dYo4tqpZms9j8aG4C",
owner: "yjzakAgYWejmJcuHz",
name: "Labbaik Waters",
peoples: [
{
profile: {firstName: "Abdul", lastName: "Hameed"},
_id: "yjzakAgYWejmJcuHz"
}
],
createdAt: "2019-09-18T15:33:29.952+00:00"
}
I ran into a similar problem couple of days ago. There are two problems with the provided code. First, using async; it's not needed and rather complicates things. Second, publishComposite relies on receiving one cursor not multiple within its children to work properly.
Below is a snippet of the code used to solve the problem I had, hopefully you can replicate it.
Meteor.publishComposite("table.conversations", function(table, ids, fields) {
if (!this.userId) {
return this.ready();
}
check(table, String);
check(ids, Array);
check(fields, Match.Optional(Object));
return {
find() {
return Conversation.find(
{
_id: {
$in: ids
}
},
{ fields }
);
},
children: [
{
find(conversation) {
// constructing one big cursor that entails all of the documents in one single go
// as publish composite cannot work with multiple cursors at once
return User.find(
{ _id: { $in: conversation.participants } },
{ fields: { profile: 1, roles: 1, emails: 1 } }
);
}
}
]
};
});

How do I get nested reference data in firestore?

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

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