Mongoose findOneandUpdate is not adding all of the fields to the document - node.js

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);
}

Related

How to update deeply nested documents in mongoose v6.2.2

I am trying to update deeply nested documents and confusing myself with all of the nesting. Below is my model and code so far. I want to update 'purchased' value of inventory based on the size variable that is passed in. I was reading about arrayFilters but I still cannot figure it out.
model:
const mongoose = require('mongoose');
const inventorySchema = new mongoose.Schema({
size: {
type: String,
},
purchased: {
type: Number,
},
used: {
type: Number,
},
});
const kidsSchema = new mongoose.Schema({
firstName: {
type: String,
trim: true,
minlength: 1,
maxlength: 99,
},
currentChild: {
type: Boolean,
},
brandPreference: {
type: String,
trim: true,
minlength: 1,
maxlength: 99,
},
currentSize: {
type: String,
},
currentSizeLabel: {
type: String,
},
lowAlert: {
type: String,
},
diaperHistory: [diaperHistorySchema],
totalPurchased: {
type: Number,
},
totalUsed: {
type: Number,
},
inventory: [inventorySchema],
});
const KidsRecordSchema = new mongoose.Schema({
kids: [kidsSchema],
});
const KidsRecord = mongoose.model('KidsRecord', KidsRecordSchema);
exports.KidsRecord = KidsRecord;
code:
/**
* #description PUT add diapers to kids inventory
*/
router.put('/update/:size', auth, async (req, res) => {
let id = req.body.user_id;
let kidID = req.body.kids_id;
let size = req.params.size;
let purchased = req.body.purchased;
try {
let record = await KidsRecord.findOne({ user_id: id });
let subRecord = record.kids.id(kidID);
let inventory = subRecord.inventory.filter((x) => x.size == size);
console.log('inventory', inventory);
// inventory give me:
// [{ "size": "0", "purchased": 0, "used": 0, "_id": "625e91571be23abeadbfbee6"}]
// which is what I want to target but then how do I apply $set to it?
// $set... ??
if (!subRecord) {
res.send({ message: 'No kids for this user.' });
return;
}
res.send(inventory);
} catch (error) {
res.send({ message: error.message });
}
});
I can drill down and find the correct inventory object I want to update, but not sure how to actually change in and save.

How to fetch mongodb documents created less than 8 hours?

Why I am not getting any results from MongoDB, I want to fetch documents which is created less than 8 hours not more than that.
let fetchAllDetails = async (findExpression) => {
try {
let data = await userDetails.find(findExpression)
return data
}
catch (err) {
logger.error(`DB Fetch All Error ---> ${JSON.stringify(err)}`)
return false
}
}
exports.remindUsers = async () => {
let currentTime = Date.now()
console.log(new Date(getCurrentTime() - 30000), new Date(getCurrentTime()))
let fetchedUserData = await fetchAllDetails({ date_time: { $gt: new Date(currentTime - 6000) } }) // For one minute
console.log(fetchedUserData)
}
MongoDB Schema
const userDetails = new mongoose.Schema({
mobileNumber: {
type: String,
required: true,
unique: true,
},
date_time: {
type: Date,
required: true,
default: Date.now()
},
});

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/

In mongoose set a field based on the value of another field in findOneAndUpdate

I'm working on a project where in one model I need to set the value of a field based on another fields value. Let me explain with some code.
Destination model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const DestinationSchema = new Schema({
name: {
type: String,
required: true
},
priority: {
type: Number,
default: 0,
max: 10,
required: true
}
})
DestinationSchema.statics.getPriority = function(value) {
return this.findOne({ _id: value })
}
const Destination = mongoose.model('Destination', DestinationSchema)
exports.Destination = Destination
Task model
const mongoose = require('mongoose')
const { Destination } = require('../_models/destination.model')
const Schema = mongoose.Schema;
const TaskSchema = new Schema({
priority: {
type: Number,
required: true,
min: 0,
max: 25
},
from: {
type: Schema.Types.ObjectId,
ref: 'Destination',
required: true
},
to: {
type: Schema.Types.ObjectId,
ref: 'Destination',
required: true
},
type: {
type: Number,
required: true,
min: 0,
max: 3
}
}, {
timestamps: true
})
TaskSchema.pre('save', async function () {
this.priority = await Destination.getPriority(this.from).then(doc => {
return doc.priority
})
this.priority += await Destination.getPriority(this.to).then(doc => {
return doc.priority
})
this.priority += this.type
})
Task Controller update function
exports.update = async function (req, res) {
try {
await Task.findOneAndUpdate({
_id: req.task._id
}, { $set: req.body }, {
new: true,
context: 'query'
})
.then(task =>
sendSuccess(res, 201, 'Task updated.')({
task
}),
throwError(500, 'sequelize error')
)
} catch (e) {
sendError(res)(e)
}
}
When I create a new Task, the priority gets set in the pre save hook just fine as expected. But I'm hitting a wall when I need to change Task.from or Task.to to another destination, then I need to recalculate the tasks priority again. I could do it on the client side, but this would lead to a concern where one could just simply send a priority in an update query to the server.
My question here is, how can I calculate the priority of a Task when it gets updated with new values for from and to? Do I have to query for the document which is about to get updated to get a reference to it or is there another cleaner way to do it, since this would lead to one additional hit to the database, and I'm trying to avoid it as much as possible.
In your task schema.
you have to use pre("findOneAndUpdate") mongoose middleware. It allows you to modify the update query before it is executed
Try This code:
TaskSchema.pre('findOneAndUpdate', async function(next) {
if(this._update.from || this._update.to) {
if(this._update.from) {
this._update.priority = await Destination.getPriority(this._update.from).then(doc => {
return doc.priority
});
}
if(this._update.to) {
this._update.priority += await Destination.getPriority(this._update.to).then(doc => {
return doc.priority
});
}
}
next();
});

Mongoose update nested array

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);
}
});

Resources