How to find or create a record with Prisma? - prisma

Is this the best way to find or create a user in Prisma?
prisma.user.upsert({
where: {
id: user.id,
},
update: {
id: user.id,
},
create: {
id: user.id,
},
})

Yes, you can use upsert to create a record. If the update property is empty, the record will not be updated.
Example:
const upsertUser = await prisma.user.upsert({
where: {
email: 'test#prisma.io',
},
update: {},
create: {
email: 'test#prisma.io',
name: 'Test User',
},
})
We plan to document this better: how upsert can behave as a findOrCreate. The link to the GitHub issue can be found here
For more information regarding upsert, you can read more in the Prisma Client API Reference section.

Related

Mongooose: How to get a id from a find array

I have a group-based document application, an error is happening in the sharing part. The application is composed of the following parts: Groups, viewers, users and documents.
A group can have many viewers and users, a user can have many documents. I'm working on the part where viewers can see all documents of users associated with the group the viewer is associated with
My controller
router.get("link", async (req, res) => {
const group = await Group.find({ viewer: req.session.userId }).select("id")
console.log(group); // This console.log returns the id in a array: [ { _id: new ObjectId("6323a88670c0dd9aaa5017d2") } ]
console.log(group.id); // This console.log returns undefined
const user = await User.find({ group: group.id });
console.log(user); // Nothing because the group.id is undefined
const documents = await Document.find({
user: user.id,
});
return res.render("page", {
documents,
});
Group schema
name: {
type: String,
required: true,
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true,
},
viewer: [{
type: mongoose.Schema.Types.ObjectId,
ref: "User",
}],
createdAt: {
type: Date,
default: Date.now,
}
I'm not able to retrieve the id from Group.find; what could be happening?
Because you want to have one value. So you can use findOne. Due to using findOne, you can reach group._id.
const group = await Group.findOne({ viewer: req.session.userId }).select("id")
console.log(group); { _id: new ObjectId("6323a88670c0dd9aaa5017d2") }
If you try to take the value from your array, you should take 0. element of array. Because it is an array and has elements. You are trying to reach element's id value.
But which element's id ? You need to declare it. Therefore, need to use group[0]._id. But if you want to reach just one element, using findOne() is better.
const group = await Group.find({ viewer: req.session.userId }).select("id")
console.log(group[0]); { _id: new ObjectId("6323a88670c0dd9aaa5017d2") }
I hope, it is clear and helps you. Good luck

Better way to perform this Relation "transaction" in Prisma

I posted a question yesterday that has the relevant prisma schema which can be found here.
As a follow up question, when a member creates a new Organization, I'd like for it to become their selected Membership. The only way I've found to do this is to deselect their current Memebership (set it to null), do the create, then restore the relationship if that create didn't work. I have to use updateMany for that initial operation in case there is no selectedMembership. Is that right?
//Deselect the currently selected Org
const updatedMembership = await prisma.membership.updateMany({
where: {
selectedById: user.id
},
data: {
selectedById: null
}
});
if (updatedMembership) {
//Select the new one.
const result = await prisma.organization.create({
data: {
name: body.name,
members: {
create: [{
role: MemberRole.OWNER,
userId: user.id,
selectedById: user.id
}]
}
},
});
if (result) {
res.status(200)
.json(result);
} else {
//Restore the previously selected one if the create failed
if(user.selectedMembership) {
await prisma.membership.update({
where: {
id: user.selectedMembership?.id
},
data: {
selectedById: user.id
}
});
}
res.status(500).end();
}
}
You can use the connect API to do all of this in a single query. Just make sure that the user.id is valid.
Here's a much cleaner version of the create and update query logic in your question:
const result = await prisma.organization.create({
data: {
name: body.name,
members: {
create: {
role: MemberRole.OWNER,
user: {
connect: {
id: user.id, // making the user a member of the organization
},
},
selectedBy: {
connect: {
id: user.id, // selecting the newly created membership as the user's default organization
},
},
},
},
},
});
This will handle all cases, regardless of whether the user with id = user.id currently:
Is a member of other organization(s) and has another membership as their default
Is a member of other organization(s) but has no default membership
Is not a member of any organization and has no default membership

Prisma splice Item from Array

I have been pushing updates to an array and was wondering if there is a built-in method to remove an entry from the array as well. Basically reversing the push command. I suspect that I have to query all documents and remove the item myself. But maybe there is some functionality I was unable to find inside the documentation.
Push:
const addTag = await prisma.post.update({
where: {
id: 9,
},
data: {
tags: {
push: 'computing',
},
},
})
Remove Expectation:
const removeTag = await prisma.post.update({
where: {
id: 9,
},
data: {
tags: {
splice: 'computing',
},
},
})
As of writing, there's no method to splice/remove items from a scalar list using Prisma. You would have to fetch the scalar list from your database, modify it manually in your application code and overwrite the record in your database with an update operation.
There is a feature request for this, please feel free to follow/comment with your use-case to help us track demand for this feature.
const { dogs } = await prisma.user.findOne({
where: {
id: userId
},
select: {
dogs: true
},
});
await prisma.user.update({
where: {
id: userId
},
data: {
dogs: {
set: dogs.filter((id) => id !== 'corgi'),
},
},
});

How to create record if it does not exist in mongodb during bulkWrite?

The server will receiving lots of data. And issue is that I need to create records if a field name of the record does not exist in the database.
I am using mongoose for performing operations with mongodb.
db.getDb(async function (error, db) {
await db._models.Model.bulkWrite(
values.map((value) => {
const instance = new db._models.Model({
__v: 0,
});
return {
updateOne: {
filter: {
title: value,
_datasetId: dataset._id,
},
update: {
$set: {
_id: instance._id,
_datasetId: dataset._id,
title: tag,
createdBy: user._id,
createdAt: date,
updatedAt: date,
__v: instance.__v,
},
},
upsert: true,
},
};
})
);
I do not want to update existing record, but to create record if it does not exist. (If record with title and _datasetId exist, it should skip the values).
How can I achieve this?
You have already set upsert:true , in case updateOne do not find the document specified by the filter it will perform insert instead of update...

Creating a many-to-many relationship in MongoDB/ Mogoose using nested fields?

I'm currently trying to wrap my head around creating a many-to-many relationship in mongodb/mongoose.
I have two Schemas:
// User Schema
var UserSchema = mongoose.Schema({
email: {
type: String,
index:true
},
name: {
type: String
},
tasks:[{type:mongoose.Schema.ObjectId, ref: 'Tasks'}]
});
and
// Tasks Schema
var TaskSchema = mongoose.Schema({
name: {
type: String,
index: true
},
description: {
type: String
},
status:{
type: String
},
});
The idea here, is that each user can take on a task and the task would have it's own status for each user (e.g. notStarted, inProgress, Complete, Failed). This status would change as the user progresses through the task. Each user would see the same tasks(i.e. name + description), but would have a different status associated with it. Additionally, each task has it's own status (Available, Hidden), which would dictate if the users can see the task or not. This would not be unique for each user.
This is my thought process so far:
I'm thinking that I can nest the objectIds of every task in with the user along with the status. For example:
{
email: "Bob#bob.com"
name: "Bob",
tasks: {
{ _id: 001, status: "Active"},
{_id: 002, status: "inProgress"},
{ _id: 003, status: "Failed"}
}
},
{
email: "Mary#mary.com"
name: "Mary",
tasks: {
{ _id: 001, status: "Failed"},
{ _id: 002, status: "Active"},
{ _id: 003, status: "Active"}
}
}
However, this means that whenever I create a new task, I need to add it to the task list of all users, with the status set to a default (e.g. notStarted). Additionally whenever I add a new user, I need to get all tasks and add them to the user's list of tasks.
This seems sort of clunky to me, and I feel like there must be a better way. If this is the best way to do it, I'm not quite sure what I would use to write this. I was thinking maybe use addFields or would Push be more appropriate? Or would that create arrays that grow without bound? which might not be the best idea since it's a Mongo anti-pattern from what I've read?
I also found this post that's sort of related, but it's from ~6 years ago, and I think I need a little bit more depth or code examples.
Any help would be much appreciated!
If you want to add new task in user whenever new task will created then your query should be :
taskCtr.create = (req, res) => {
const {
name,
description,
status
} = req.body;
TaskSchema.create({
name,
description,
status
}).then((result) => {
if (result) {
UserSchema.update({}, {
$push: {
tasks: {
_id: result._id,
status: result.status
}
}
}, {
multi: true
}).then((userUpdated) => {
res.status(200).json({
message: 'A new Task created successfully!'
})
}).catch((err) => {
res.status(500).json({
error: 'Internal server error!'
});
});
}
}).catch((err) => {
res.status(500).json({
error: 'Internal server error!'
});
});
};