Mongoose update nested array - node.js

In the schema, I have an object defender.placements.cruisers: []
i try to insert obj to it but it insert only status, direction, size but empty grids then i try to update again it remove the old data (status, direction, size) and insert new data
//My Model
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
export const CoordinateSchema = new Schema({row: Number, col: Number});
export const ShipSchema = new Schema({
grids: [CoordinateSchema],
status: String,
direction: String,
size: Number
});
export const GameStateSchema = new Schema({
gameState: {
type: String,
required: 'state status',
default: 'joining'
},
attacker: {
hitGrids: [CoordinateSchema],
missGrids: [CoordinateSchema]
},
defender: {
placements: {
battleships: [ShipSchema],
cruisers: [ShipSchema],
destroyers: [ShipSchema],
submarines: [ShipSchema]
}
},
occupyGrids: [CoordinateSchema],
adjacentGrids: [CoordinateSchema],
size: {
type: String,
default: '10'
}
});
export default mongoose.model('GameState', GameStateSchema);
below, the code that i try to push data to array in
await GameState.update({
_id: testId
},{
$set: {
'defender.placements': {
[shipType]: {
status: utils.shipStatus.float,
direction: shipDirection,
size: coordinates.length,
$addToSet: {
grids: coordinates
}
}
}
},
$addToSet: {
occupyGrids: coordinates,
adjacentGrids: closeGrids
}
}, (err, gm) => {
if (err) {
return res.send(err);
}
});
here is my result that i got but

it works
const newPlacements = [{
grids: [...coordinates],
status: utils.shipStatus.float,
direction: shipDirection,
size: coordinates.length
}];
const keyPlacements = `defender.placements.${shipType}`;
await GameState.update({
_id: testId
},{
$addToSet: {
[keyPlacements]: newPlacements,
occupyGrids: coordinates,
adjacentGrids: closeGrids
}
}, (err, gm) => {
if (err) {
return res.send(err);
}
});

Related

How do I update nested array values in mongoose?

I am fairly new to nodejs/express and I'm practicing full stack development with devchallenges.io, i'm doing the shoppingify challenge. I'm trying to update the quantity of an item I am targeting inside of the items array. I understand my attempt below was terrible, I'm really struggling to understand the logic to be able to do so.
// #route PUT api/list/item/quantity/:id
// #desc Increase or decrease quantity
// #access Private
router.put('/item/quantity/:id', auth, async (req, res) => {
const { action } = req.body;
try {
let list = await List.findOne({ user: req.user.id });
const item = list.items.find(
(item) => item._id.toString() === req.params.id
);
list = list.updateOne(
{ 'items._id': req.params.id },
{ $set: { 'items.quantity': item.quantity + 1 } }
);
await list.save();
return res.json(list);
} catch (error) {
console.error(error.message);
res.status(500).send('Server Error');
}
});
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ListSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
},
name: {
type: String,
default: 'Shopping List',
},
items: [
{
name: {
type: String,
default: '',
},
note: {
type: String,
default: '',
},
image: {
type: String,
default: '',
},
category: {
type: String,
default: '',
},
quantity: {
type: Number,
default: 1,
},
},
],
date: {
type: Date,
default: Date.now,
},
});
module.exports = List = mongoose.model('list', ListSchema);
Look this is my update-vendor route here I'm updating nested street and city name.
router.put("/update-vendors", async (req, res, next) => {
const vendor = await Vendor.updateOne(
{
"address.street": "Street2",
},
{
$set: {
"address.$.street": req.body.street,
"address.$.city": req.body.city,
},
}
);
res.status(200).json(vendor);
});
You can update particular things with the help of $set and other $push method

MongoDB array of objects update

I'm trying to update array of user information objects in mongoose.
I've stored the user core information in the login process, I want to update some of user information when user tries to make an order.
Here is the code for the model
const mongoose = require('mongoose');
const { ObjectId } = mongoose.Schema;
const userSchema = new mongoose.Schema(
{
name: String,
email: {
type: String,
required: true,
index: true,
},
role: {
type: String,
default: 'subscriber',
},
info: [
{ country: String },
{ city: String },
{ address: String },
{ phone: String },
{ birthdate: Date },
{ gender: { type: String, enum: ['Male', 'Female'] } },
],
// wishlist: [{ type: ObjectId, ref: "Product" }],
},
{ timestamps: true }
);
module.exports = mongoose.model('User', userSchema);
In my controller I'm getting the data from front-end react app as JSON format, I want to push some data to info which is an array of objects in the users model above.
exports.createOrder = async (req, res) => {
// Here I constract the data
const { plan, service, fullName, country, city, address } = req.body.order;
const { user_id } = req.body;
// This the method I tried
try {
const user = await User.updateOne(
{
_id: user_id,
},
{
$set: {
'info.$.country': country,
'info.$.city': city,
'info.$.address': address,
},
},
{ new: true }
);
if (user) {
console.log('USER UPDATED', user);
res.json(user);
} else {
res.json((err) => {
console.log(err);
});
}
const newOrder = await new Order({
orderPlan: plan,
orderService: service,
orderUser: user_id,
}).save();
console.log(newOrder);
console.log(req.body);
} catch (error) {
console.log(error);
}
};
I tired other solutions like
const user = await User.updateOne(
{
_id: user_id,
info: { $elemMatch: { country, city, address } },
},
{ new: true }
);
So do I need to reformat my model or there is a way to update this array of objects?
Option 1
Use $[]
db.collection.update(
{},
{ $set: { "info.$[i].country": "a1" }} ,
{ arrayFilters: [ { "i.country": "a" } ] }
)
Demo - https://mongoplayground.net/p/UMxdpyiKpa9
Option 2
if you know the index
Demo - https://mongoplayground.net/p/41S7qs6cYPT
db.collection.update({},
{
$set: {
"info.0.country": "a1",
"info.1.city": "b1",
"info.2.address": "c1",
"info.3.phone": "d1"
}
})
Suggestions -
Change info schema to object instead of an array

Mongoose findOneandUpdate is not adding all of the fields to the document

Ok, so I have burnt hours on this and multiple various google searches, and I can't seem to solve this. So, I'm here for some help...
I am trying to use mongoose.findOneAndUpdate() to either add a document or update an existing document into a collection. I have done this many times before successfully, but I am stumped right now.
When the document is created in the mongodb it contains only this:
{
_id: <some mongo id>
faFlightID: 4839-fjgnkbk-adhoc
positions: [Array of Objects] <----These appear to be correct.
}
That's it. It is missing all of the other fields. I feel like I am missing something completely and totally obvious, but at this point I've been staring at it for so long, I probably can't see the forest for the trees
Here is my mongoose code:
const Flights = require('../models/faFlights.model');
const saveFlight = async (flight) => {
let position = {
timestamp: flight.timestamp,
longitude: flight.longitude,
latitude: flight.latitude,
groundspeed: flight.groundspeed,
altitude: flight.altitude,
heading: flight.heading,
altitudeStatus: flight.altitudeStatus,
altitudeChange: flight.altitudeChange,
};
const filter = { faFlightID: flight.faFlightID };
const update = { flight, $push: { positions: position } };
try {
let result = await Flights.findOneAndUpdate(filter, update {
upsert: true,
new: true,
});
console.log(result);
} catch (error) {
console.log(error);
}
};
And here is my faflights.model
const mongoose = require('mongoose');
const positionSchema = new mongoose.Schema({
timestamp: {
type: Date,
set: (d) => formatEpoch(d),
},
longitude: Number,
latitude: Number,
groundspeed: Number,
altitude: Number,
heading: Number,
altitudeStatus: String,
altitudeChange: String,
});
const faflightSchema = new mongoose.Schema(
{
TALON_ACT_ID: String,
faFlightID: String,
ident: {
type: String,
set: (acreg) => modifyACRegistration(acreg),
},
prefix: String,
type: String,
suffix: String,
origin: String,
destination: String,
timeout: Number,
departureTime: {
type: Date,
set: (d) => formatEpoch(d),
},
firstPositionTime: {
type: Date,
set: (d) => formatEpoch(d),
},
arrivalTime: {
type: Date,
set: (d) => formatEpoch(d),
},
positions: [positionSchema],
lowLongitude: Number,
lowLatitude: Number,
highLongitude: Number,
highLatitude: Number,
updateType: String,
waypoints: String,
},
{ collection: 'faflights' }
);
//Convert AC Registration formatting
const modifyACRegistration = (reg) => {
let firstCharacter = reg.substring(0, 1);
let remainingCharacter = reg.substring(1, 5);
return `${firstCharacter}-${remainingCharacter}`;
};
const formatEpoch = (epoch) => {
if (!epoch) return;
return new Date(epoch * 1000);
};
module.exports = mongoose.model('faflights', faflightSchema);
I am at a total loss.
Apparently, I just needed to leave my workstation for a while, or more coffee...or both. Needed to use $set to make it all better.
const filter = { faFlightID: flight.faFlightID };
const update = { $set: flight, $push: { positions: position } };
try {
let result = await Flights.findOneAndUpdate(filter, update {
upsert: true,
new: true,
});
console.log(result);
} catch (error) {
console.log(error);
}

In Mongoose findOneAndUpdate, how can I make my post request work?

Hi all so I am trying to make a post request that increments a value if it already exists and if not it should create a new item.
router.post('/', auth, async (req, res) => {
try {
const { name, price, image } = req.body;
var query = { name },
update = { $inc: { count: 1 } },
options = { upsert: true, new: true,};
await CartItem.findOneAndUpdate(query, update, options, function (
err,
data
) {
if (err) {
const newItem = new CartItem({
user: req.user.id,
name: name,
price: price,
image: image,
});
const item = newItem.save();
res.json(item);
} else {
res.json(data);
}
});
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const CartItemSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'user',
},
name: {
type: String,
required: true,
},
price: {
type: Number,
required: true,
},
count: {
type: Number,
},
image: {
type: String,
required: true,
},
});
module.exports = CartItem = mongoose.model('cartItem', CartItemSchema);
So there are two problems here that I cannot wrap my head around(Pretty new with MongoDb, did do my research).
I can get the count to increment, but it increments with 2 or even more instead of 1. (I know other users also experienced this)
If the item is already in the cart(name matches) I want a new item to be added which does happen, but it only adds the name, count and Id. I want it to add the user, name, price and image.
Would appreciate some assistance.
you should create your document with a default value equals to 0.
define count at your schema like the following:
count: {
type: Number,
default: 0
}
then use { $inc: { <field1>: <amount1>, <field2>: <amount2>, ... } }.
link to docs: https://docs.mongodb.com/manual/reference/operator/update/inc/

MongoDB $push is not actually pushing anything onto the array

I commented the line of code with // This Command Does not work where I suspect that it is breaking. In the debug log of mongoose, the output looks like this: But nothing is added to the medicineIds array in the Monday object for the DaysOfWeek schema.
The following is the debug output for DayOfWeek.findOneAndUpdate() where I push back onto the array, and am not seeing the result in my mongo database.
Mongoose: dayofweeks.insertOne({ medicineIds: [], _id: 'Monday', __v: 0 }, { session: null }) // <- response to $push
Mongoose: medicines.insertOne({ times: [ 1, 2 ], dayNames: [ 'Monday' ], _id: ObjectId("5e73d816d54b1202e15bb96b"), nam
e: 'Provolone', count: 23, __v: 0 }, { session: null })
Mongoose: dayofweeks.findOne({ _id: 'Monday' }, { projection: {} })
Mutation
const Mutation = new GraphQLObjectType({
name: 'Mutation',
fields: {
addDayOfWeek: {
type: DayOfWeekType,
args: {
name: { type: new GraphQLNonNull(GraphQLString) }
},
resolve(parent, args) {
let dayOfWeek = new DayOfWeek({
_id: args.name,
medicineIds: new Array()
});
return dayOfWeek.save();
}
},
addNewMedicine: {
type: MedicineType,
args: {
name: { type: new GraphQLNonNull(GraphQLString) },
count: { type: new GraphQLNonNull(GraphQLInt) },
times: { type: new GraphQLNonNull(GraphQLList(GraphQLInt))},
dayNames: { type: new GraphQLNonNull(GraphQLList(GraphQLString))}
},
resolve (parent, args) {
let medicine = new Medicine({
name: args.name,
count: args.count,
times: args.times,
dayNames: args.dayNames
});
args.dayNames.forEach((dayId) => {
DayOfWeek.findOneAndUpdate( // This Command Does Not Work:
// medicine._id, dayId are correct at this point of the
//code
{ _id: dayId },
{ $push: { medicineIds: medicine._id }},
{ new: true, useFindAndModify: false }
);
});
return medicine.save();
}
}
}
});
DayOfWeek Schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const dayOfWeekSchema = new Schema({
_id: String,
medicineIds: [String] // I am trying to push onto this array
});
module.exports = mongoose.model('DayOfWeek', dayOfWeekSchema);
Medicine Schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const medicineSchema = new Schema({
id: String,
count: Number,
name: String,
times: [Number],
dayNames: [String]
});
module.exports = mongoose.model('Medicine', medicineSchema);
await Promise.all(args.dayNames.map(dayName => {
return DayOfWeek.findOneAndUpdate({ _id: dayName }, { $push: { medicineIds: medicine._id }});
})).catch((err) => console.error(err));
return await medicine.save();
I just did that and it works. hmm.

Resources