How to insert value in a nested mongodb document? - javascript

I have this document:
{
"_id": {
"$oid": "63cf19337c2df5fe442a2b69"
},
"createdAt": {
"$date": {
"$numberLong": "1674516787623"
}
},
"updatedAt": {
"$date": {
"$numberLong": "1675035206032"
}
},
"clientIp": "89.132.225.21",
"products": {
"6cc5a480-91f0-4aa8-975c-013d6bd155a3": {
"currency": "EUR",
"title": "VVV",
"price": "12",
"barionId": "aa#aa.hu",
"ratingTimeLength": 12
}
}
}
I would insert like this:
const userId = req.query.userId
const productId = req.query.productId
const token = authorization.slice(7)
const userJWT = jwt.verify(token, process.env.JWT_SECRET) as JwtPayload
const ObjectId = require('mongodb').ObjectId
const id = new ObjectId().toHexString()
await collection.updateOne(
{ _id: ObjectId(userId), [`products.${productId}`]: { $exists: true } },
{
$set: {
[`products.$.payments.${id}`]: {
createdAt: new Date(),
createdBy: userJWT.userId,
},
},
},
{ upsert: true }
)
But it raise:
2023-01-29T23:43:33.653Z 1a42849c-d5aa-4127-8fdc-9169c1c6c405 ERROR MongoServerError: The positional operator did not find the match needed from the query.
When I query record in Compass, it returns the document:
{
"_id": ObjectId("63cf19337c2df5fe442a2b69"),
"products.6cc5a480-91f0-4aa8-975c-013d6bd155a3": {
"$exists": true
}
}
What is wrong?

You should access the products property directly with:
await collection.updateOne(
{ _id: ObjectId(userId), [`products.${productId}`]: { $exists: true } },
{
$set: {
[`products.payments.${id}`]: {
createdAt: new Date(),
createdBy: userJWT.userId,
},
},
},
{ upsert: true }
);

Related

Mongoose, updated nested array

My question is:
How can I query in the nested arrays?
I want to change value in key "likeUp" which is nested inside object in array "usersWhoLiked". Where "usersWhoLiked" is nested in array "comments"
How Can I do that with mongoose ?
Request that I wrote beneath... do not work, but is very similar to answer given in StackOverflow post: Mongoose update update nested object inside an array
This is my request to db with updateOne:
try {
const response = await Comments.updateOne(
{
productId,
comments: { $elemMatch: { usersWhoLiked: { $elemMatch: { userId } } } },
},
{
$set: { 'comments.$[outer].usersWhoLiked.$[inner].likeUp': likes.up },
},
{
arrayFilters: [{ 'outer._id': commentId }, { 'inner._userId': userId }],
}
).exec();
return res.status(201).json({ response });
} catch (err) {
console.log(err);
return res.send(err);
}
This is the collection, that I am trying to update:
{
"_id": {
"$oid": "6307569d2308b78b378cc802"
},
"productId": "629da4b6634d5d11a859d729",
"comments": [
{
"userId": "62f29c2c324f4778dff443f6",
"userName": "User",
"date": "2022.08.25",
"confirmed": true,
"likes": {
"up": 0,
"down": 0
},
"content": {
"rating": 5,
"description": "Nowy komentarz"
},
"_id": {
"$oid": "630756b22308b78b378cc809"
},
"usersWhoLiked": [
{
"userId": "62f29c2c324f4778dff443f1",
"likeUp": true,
"_id": {
"$oid": "6307572d2308b78b378cc80e"
}
},
{
"userId": "62f29c2c324f4778dff443f2",
"likeUp": true,
"_id": {
"$oid": "6307572d2308b78b378cc80c"
}
}
]
}
],
"__v": 0
}
Mongooes schema for comment collection:
const commentSchema = new Schema({
productId: String,
comments: [
{
userId: String,
userName: String,
date: String,
confirmed: Boolean,
likes: {
up: {
type: Number,
default: 0,
},
down: {
type: Number,
default: 0,
},
},
content: {
rating: Number,
description: String,
},
usersWhoLiked: [{ userId: String, likeUp: Boolean }],
},
],
});
I guess the problem is with your arrayFilters operator, because you are trying to filter by field _userId which does not exist:
arrayFilters: [{ 'outer._id': commentId }, { 'inner._userId': userId }],
I managed to update the likeUp value using the following query:
db.collection.update({
_id: ObjectId("6307569d2308b78b378cc802")
},
{
$set: {
"comments.$[user].usersWhoLiked.$[like].likeUp": false
}
},
{
arrayFilters: [
{
"user._id": ObjectId("630756b22308b78b378cc809")
},
{
"like.userId": "62f29c2c324f4778dff443f1"
}
]
})
Try it on MongoDB playground: https://mongoplayground.net/p/XhQMNBgEdhp

Mongoose ignoring field while trying to save

I am trying to insert a new entry in my collection, the problem is that it ignores both doctorId and patientId while I'am sure they are not undefined. I tried to change the fields types in the definition to strings just to test whether they would be inserted and it still no use.
schema:
const RdvSchema = new mongoose.Schema({
patientId: {
type: mongoose.Schema.Types.ObjectId,
ref: "patients"
},
doctorId: {
type: mongoose.Schema.Types.ObjectId,
ref: "doctors"
},
createdAt: {
type: Date,
default: () => Date.now()
},
updatedAt: {
type: Date,
default: () => Date.now()
},
urgent: {
type: Number,
default: () => false
},
date: Date,
period: String,
description: String
})
the function saving the document:
const createRdv = async (req, res) => {
try {
console.log("patient id: ", req.body.patientId)
let rdv = new Rdv({
"patientId": req.body.patientId,
"doctorId": req.body.doctorId,
"description": req.body.description,
"urgent": req.body.urgent,
"date": req.body.date,
"period": req.body.period
})
await rdv.save(async (err, rdv) => {
if (err) {
console.log(err)
return res.status(500).send(false)
}
try {
await DoctorRepository.addRdv(req.body.doctorId, rdv._id)
await PatientRepository.addRdv(req.body.patientId, rdv._id)
} catch (message) {
console.log(message)
res.status(500).send(false)
}
})
res.status(200).send(true)
} catch (ex) {
res.status(500).send(false)
}
}
The inserted document:
{
"_id": {
"$oid": "6269603d5f0e45e53a470f50"
},
"urgent": 3,
"date": {
"$date": {
"$numberLong": "1653433200000"
}
},
"period": "matin",
"description": "this is a description",
"createdAt": {
"$date": {
"$numberLong": "1651073085661"
}
},
"updatedAt": {
"$date": {
"$numberLong": "1651073085661"
}
},
"__v": 0
}
update: for some reason An old document keeps getting inserted the document has nothing to do with what I was trying to insert. The document is one I had inserted previously through a test using Mocha

MongooseJS: How to remove 1 object inside Array in Array of Objects

Hi MongooseJS experts!
I'm new in MongooseJS, This is my 2nd day of solving this problem but I can't find a working solution to this.
Thank you in advance!
My Delete method
Cart.updateOne(
{ "content.merchantId": req.body.merchantId },
{ $pull: { "content.items._id": req.body.productId } },
{ new: true },
function (error, result) {
if (error) { }
else if (result) { }
}
);
Schema
const CartSchema = new Schema({
customerId: {
type: String,
required: true,
},
content: {
merchantName: {
type: String,
required: true,
},
merchantId: {
type: String,
required: true,
},
items: [],
},
});
Sample JSON
[
{
"content": {
"merchantName": "SAMPLE_MERCHANT_NAME",
"merchantId": "SAMPLE_MERCHANT_ID",
"items": [
{
"_id": "SAMPLE_ID",
"title": "SAMPLE TITLE",
}
]
},
"_id": "618220e83966345ab5d451cd",
"__v": 0
},
]
Error message
Cannot use the part (_id) of (content.items._id) to traverse the element ({items: [{ _id: "SAMPLE_ID", title: "SAMPLE TITLE"}] })
you should use like this
db.collection.update({
"content.merchantId": "SAMPLE_MERCHANT_ID"
},
{
$pull: {
"content.items": {
"_id": "SAMPLE_ID"
}
}
},
{
new:true
},
)
https://mongoplayground.net/p/Ou26tab2mBU

Mongo Aggregation problem, want to avoid outter wrapper

my goal is to update the active property within the weeks object, instead i get another object wrapper.
How i can either avoid this behavior or rewrite the aggregation to get the values from the weeks object in the wrapper?
{
"weeks": {
"time": [
"06",
"00"
],
"active": true,
"reason": "",
"bookTime": 202102260600,
"qdate": 20210226,
"booked": false
},
"active": false
},
]
My aggregation pipeline:
const company = await Company.aggregate([
{ $match: { email: 'test#gmail.com' } },
{ $unwind: '$weeks' },
{ $match: { 'weeks.qdate': { $gte: 20210226, $lte: 20210305 } } },
{ $unset: '_id' },
{
$project: {
weeks: 1,
active: {
$cond: {
if: { $lt: ['$weeks.bookTime', 202102261445] },
then: false,
else: true,
},
},
},
},
]);
I forgot that i need to add the $ sign on nested objects.
So the final pipeline will look like this.
const company = await Company.aggregate([
{ $match: { email: 'test#gmail.com' } },
{ $unwind: '$weeks' },
{ $match: { 'weeks.qdate': { $gte: 20210226, $lte: 20210305 } } },
{ $unset: '_id' },
// { $group: { _id: { time: '$weeks.bookTime' } } },
{
$project: {
bookTime: '$weeks.bookTime',
utc: '$weeks.utc',
booked: '$weeks.booked',
active: {
$cond: {
if: { $lt: ['$weeks.bookTime', 202102261445] },
then: false,
else: true,
},
},
},
},
]);

Convert Date to String in nested array in mongodb

I have a mongodb collection called cases and inside cases I have an array of cases per company object.
So the structure is:
Inside each case I want to use the createddate (which is a string) and endDate (also string) and convert it to a mongodb date.
When I use NoSQLBooster I add the following query:
db.cases.aggregate([
{ $match: { companyID: 218 }},
{ $unwind: "$cases" },
{ $match: { 'cases.id': '299' }},
{ $addFields: { 'cases.created': new Date('2010-06-21T00:00:00.000'), 'cases.closed': new Date('2014-08-29T00:00:00.000') }},
{ $group: { _id: "$_id", cases: { $push: "$cases" }}}])
This will add a date in a new field - created and then closed. This is exactly what I want.
However, in my code (using mongoose) I have the following:
scripts.commponent.ts:
runThroughCasesAndConvertDates(id) {
this.scriptsService.getAllCasesToModify({ companyID : id}).subscribe( res => {
if (res.length > 0) {
for (let i = 0; i < res[0].cases.length; i++) {
const caseID = res[0].cases[i].id;
const data = {
companyID: id,
caseID: caseID,
created: moment(res[0].cases[i].createddate, 'DD-MMM-YYYY h:mm a').format('YYYY-MM-DD[T00:00:00.000Z]'),
closed: ''
};
if (res[0].cases[i].endDate !== '') {
data.closed = moment(res[0].cases[i].endDate, 'DD-MMM-YYYY h:mm a').format('YYYY-MM-DD[T00:00:00.000Z]');
}
this.scriptsService.updateDates(data).subscribe();
}
}
});
}
scripts.service.ts
updateDates(body) {
return this.http.post('/db/cases/updateAllDates', body).pipe(
map(res => res.json())
);
}
casesDB.js
router.post('/updateAllDates', (req, res) => {
const { body } = req;
Cases.aggregate([
{ $match: { companyID: body.companyID }},
{ $unwind: "$cases" },
{ $match: { 'cases.id': body.caseID }},
{ $addFields: { 'cases.created': new Date(body.created), 'cases.closed': new Date(body.closed) } },
{ $group: { _id: "$_id" }
}],
function (err, data) {
res.json(data)
});
});
But it does not add anything into the array. Im really confused as to what Im doing wrong. Maybe there is a better way / approach to doing this?
Thank you
You can $map over the cases array and can change the date string fields to date object fields.
Cases.aggregate([
{ "$addFields": {
"cases": {
"$map": {
"input": "$cases",
"in": {
"$mergeObjects": [
"$$this",
{
"createddate": {
"$dateFromString": { "dateString": "$$this.createddate" }
},
"endDate": {
"$dateFromString": { "dateString": "$$this.endDate" }
}
}
]
}
}
}
}}
])
Update: If dates are blank string
Cases.aggregate([
{ "$addFields": {
"cases": {
"$map": {
"input": "$cases",
"in": {
"$mergeObjects": [
"$$this",
{
"createddate": {
"$cond": [
{ "$eq": ["$$this.createddate", ""] },
null
{ "$dateFromString": { "dateString": "$$this.createddate" } }
]
},
"endDate": {
"$cond": [
{ "$eq": ["$$this.endDate", ""] },
null
{ "$dateFromString": { "dateString": "$$this.endDate" } }
]
}
}
]
}
}
}
}}
])

Categories

Resources