Adding multiple items to mongodb - mongodb

I have this schema with
const userSchema = new mongoose.Schema(
{
skills: [{ name: { type: String, unique: true }, level: { type: Number } }],
and I am trying, after getting an array of objects from the client, to add all of them at once under a user in MongoDB
my old implementation when it was only an array is this one below. I have no idea how to go about it now tho. Could anyone help me?
const { email } = session;
const { skill } = req.body;
if (req.method === 'POST') {
try {
const user = await User.findOne({ email });
const updatedUser = await User.findOneAndUpdate(
{ email },
{ skills: [...user.skills, { name: skill }] }
);

const { email } = session;
// object from the client
const { skills } = req.body;
if (req.method === 'POST') {
try {
const updatedUser = await User.findOneAndUpdate(
{ email },
{ $set: {skills} }
);
the best is getting the array correctly formatted from front-end, if not use a map before call findOneAndUpdate

Related

Why is my mongoose populate not retrieving the nested array?

I have the following mongoose schemas:
const CategoriesSchema = new mongoose.Schema(
{
sites: [
{
site: {
type: ObjectId,
ref: "Sites",
}
}
],
);
mongoose.model("Categories", CategoriesSchema, 'organizer-categories');
And:
const SitesSchema = new Schema({
url: {
type: String,
required: true,
},
img: {
type: String,
},
});
mongoose.model("Sites", SitesSchema, "organizer-sites");,
The following function is supposed to create a new site in mongodb, add the site to Categories as shown in the schema and return the updated category with the new site data using mongoose's populate method. But only the _id of site is being returned with the category data.
exports.addSite = async (req, res) => {
const {categoryId, siteUrl} = req.body;
console.log('categoryId, siteUrl', categoryId, siteUrl)
try {
let site = await Sites.findOne({url: siteUrl});
console.log('site', site)
if(site) {
return res.status(422).send(`${siteUrl} already exists.`)
}
site = await Sites.create({url: siteUrl, categoryId});
// site = {url: siteUrl, categoryId};
const category = await Categories.findOneAndUpdate({
_id: categoryId
}, {
$addToSet: {
sites: site
}
}, {
new: true
}).populate({
path: 'sites.site',
model: 'Sites'
})
console.log('category', category)
res.status(201).json(category);
} catch(error) {
console.error(error);
return res.status(500).send('Error adding category.')
}
}

How find in mongoose by an array property

I have defined my Conversation scheme like this:
const { Schema, model } = require("mongoose");
const ConversationSchema = Schema(
{
members: {
type: Array,
},
},
{ timestamps: true }
);
module.exports = model("Conversation", ConversationSchema);
My problem is that when I want to create a conversation model I search first if there is already a conversation.
const newConversation = async (req, res = response) => {
try {
const { senderId, receiverId } = req.body;
const conversation = await Conversation.find({
members: { $in: [senderId, receiverId] },
});
if (conversation.length === 0) {
const dbConversation = new Conversation({
members: [senderId, receiverId],
});
await dbConversation.save();
return res.status(201).json({
ok: true,
conversation: dbConversation
});
} else {
return res.status(403).json({
ok: false,
msg: "Conversation already exist",
});
}
} catch (err) {
return res.status(500).json({
ok: false,
msg: "Please contact with administrator",
});
}
};
senderId and receivedId are the ids of the users that are in that conversation, but it doesn't work.
How can I make it check if there is already a conversation with both ids?
Per the comments, we came to understand that the thing that wasn't working about the current code was always taking the code path that returned the message that the "Conversation already exist". This meant that the following query was always returning data:
const conversation = await Conversation.find({
members: { $in: [senderId, receiverId] },
});
The logic here does not match the logic implied in the question. This syntax uses the $in operator to find documents whose members array has at least one of the values passed to it (here the senderId and the receiverId).
To instead find documents where both of those people are present in the members array, you want to use the $all operator instead:
const conversation = await Conversation.find({
members: { $all: [senderId, receiverId] },
});
Working Mongo Playground example here.

How to create dynamic query in mongoose for update. i want to update multiple data(Not all) with the help of Id

If I'm doing this, the field which I don't want to update is showing undefined. Any solution? (Like generating dynamic query or something)
exports.updateStudentById = async (req, res) => {
try {
const updateAllField = {
first_name: req.body.first_name,
last_name: req.body.last_name,
field_of_study: req.body.field_of_study,
age: req.body.age,
};
const data = await student_master.updateOne(
{ _id: req.body._id },
{ $set: updateAllField }
);
res.json({ message: "Student Data Updated", data: data });
} catch (error) {
throw new Error(error);
}
};
You can go for a dynamic query creation .Example
const requestBody = {
first_name: "John",
last_name: "Cena",
field_of_study: ""
}
const query={};
if(requestBody.first_name){
query["first_name"]=requestBody.first_name
}
if(requestBody.last_name){
query["last_name"]=requestBody.last_name
}
Check for the fields that are present in req.body and create a dynamic query
and when updating using mongoose use this
const data = await student_master.updateOne(
{ _id: req.body._id },
{ $set: query }
);
In this way only those fields would be updated which are present in your req.body

Using output of one mongoose query for the input of another in express (async/await)

I am using express and mongoose to implement a server/db. I have a working route that gets all the games involving a player by playerID. I am now trying to implement one that can take username instead of playerID.
PLAYER_SCHEMA:
const mongoose = require('mongoose');
const PlayerSchema = mongoose.Schema( {
username: {
type:String,
required:true,
unique:true
},
date_registered: {
type: Date,
default:Date.now
}
});
module.exports = mongoose.model('Player', PlayerSchema);
GAME_SCHEMA:
const mongoose = require('mongoose');
const GameSchema = mongoose.Schema( {
player_1: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Player',
required: true
},
player_2: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Player',
required: true
},
status: {
type:String,
},
hero_1: {
type:String
},
hero_2: {
type:String
},
date_registered: {
type: Date,
default:Date.now
}
});
module.exports = mongoose.model('Game', GameSchema);
Here's what I have to query all games involving a player by playerId:
//GET GAMES INVOLVING PLAYER BY PLAYER_ID
router.get('/player/:playerId', async (req, res) => {
try {
const games = await Game.find({$or:[{ player_1: req.params.playerId }, { player_2: req.params.playerId}]});
console.log(games)
res.json(games);
// weird cuz doesn't throw error if not found, just returns empty list...
}
catch (err) {
res.json({ message: err });
}
});
The following outlines what I want to do, but it doesn't work, for I'm sure many reasons:
I am trying to get the userId from username first, then pass that into a query for the games.
//GET ALL GAMES ASSOCIATED WITH PLAYER BY USERNAME
router.get('/username/:username', async (req, res) => {
try {
const player = await Player.findOne({username:req.params.username});
console.log(player);
const games = Game.find({ $or:[{ player_1: player._id }, { player_2: player._id }] });
res.json(games);
}
catch (err) {
res.json({ message: err });
}
});
I've been reading about .populate(), promises, and waterfalls, but I'm new to this and would love some guidance!
Please try this :
//GET ALL GAMES ASSOCIATED WITH PLAYER BY USERNAME
router.get('/username/:username', async (req, res) => {
try {
const player = await Player.findOne({ username: req.params.username });
console.log(player);
/**
* .findOne() should return a document or null - if no match found..
*/
if (player) {
/**
* .find() will return empty [] only if it didn't find any matching docs but won't throw an error in successful DB operation
* (irrespective of whether docs matched or not, if op is successful then there will be no error).
*/
const games = await Game.find({ $or: [{ player_1: player._id }, { player_2: player._id }] }).lean();
(games.length) ? res.json(games) : res.json(`No games found for ${player._id}`);
} else {
res.json('No player found')
}
}
catch (err) {
res.json({ message: err });
}
});

How create relationship between two collections

I'm creating server app using nodejs(express) and mongodb(mongoose). I must create relationships between Organization model and Users model. After creating an organization, I want to create a user that will apply to a specific organization. One user can apply to many organizations. How can I do this?
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
// UserShema
const UserSchema = Schema({
login: {
type: String,
require: true,
unique: true
},
password: {
type: String,
require: true
},
organization: {
ref: "Organization",
type: Schema.Types.ObjectId
}
});
// Organization Schema
const OrganizationSchema = Schema({
label: {
type: String
},
users: [{
type: Schema.Types.ObjectId,
ref: "Users"
}]
});
//For now I have simple route for creating an Organization.
// request:
// {
// "label": "testOrg"
// }
exports.createOrganization = async (req, res) => {
try {
const org = await new Organization(req.body);
await org.save();
} catch (error) {
return res.status(500).json({error})
}
}
//And I have this route for user registration
exports.signup = async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
};
const {login} = req.body;
try {
const checkUser = await Users.findOne({login});
if (!checkUser) {
const user = await new Users(req.body);
await user.save();
return res.status(200).json({ user });
} else {
return res.status(400).json({error: "User already exist"})
}
} catch (error) {
return res.status(500).json({error})
}
};
You could embed the organization id into a string into the user document
Like this {
name: "Name",
location: "CA",
organizations: [123456789, 234567890, ...]
}