unable to update a subdocuments in an array - mongodb

im trying to update a value for uid in solts.slots but nothing works.
i want to iterate two level of array to modify the document
{
"_id": {
"$oid": "638455dee12f0122c9812697"
},
"bid": "637b0fdd3d9a96eb913805d3",
"name": "sucess",
"slots": [
{
"date": "2022-11-28T00:00:00.000Z",
"slots": [
{
"uid": null,
"available": true,
"status": null,
"_id": {
"$oid": "638455dee12f0122c98126a0"
}
},
{
"uid": null,
"available": true,
"status": null,
"_id": {
"$oid": "638455dee12f0122c98126a1"
}
}
],
"_id": {
"$oid": "638455dee12f0122c9812698"
}
}
]}]}
im trying to update the slots for id 638455dee12f0122c98126a0 properties like
uid:'234235'
available:false
status:'booked'
can anyone help me to query this
i tried
const result = await Event.findOne({
'slots.slots': {
$elemMatch: {
_id: req.body.id
}
}
})
is there is any way to query this type of documents.

You can use $[] and $[<identifier>]:
db.collection.update({
"slots.slots": {
$elemMatch: {
_id: ObjectId("638455dee12f0122c98126a0")
}
}
},
{
$set: {
"slots.$[].slots.$[item].available": false,
"slots.$[].slots.$[item].uid": "234235",
"slots.$[].slots.$[item].status": "booked"
}
},
{
arrayFilters: [
{
"item._id": ObjectId("638455dee12f0122c98126a0")
}
]
})
See how it works on the playground example

Related

Return the result of an aggregate as an object not an array

I have models in my collection this way..
{
"_id": {
"$oid": "5f213786d0cdd10c61969fc7"
},
"stationStatus": "Online",
"metadata": {
"SerialNumber": "BP001",
"imsi": "082943327103528941"
},
"boxIdentity": "BP001",
"__v": 0
}
{
"_id": {
"$oid": "5f213786d0cdd10c61969fc7"
},
"stationStatus": "Offline",
"metadata": {
"SerialNumber": "BP002",
"imsi": "082943327103528941"
},
"boxIdentity": "BP002",
"__v": 0
}
This is the aggregation i'm performing on the data.
var aggregation = [
{
$project: { __v: false },
},
{
$group: {
_id: { $toLower: "$stationStatus" },
stations: {
$push: "$$ROOT",
},
},
},
{
$group: {
_id: null,
stations: {
$push: {
k: "$_id",
v: "$stations",
},
},
},
},
{
$replaceRoot: {
newRoot: { $arrayToObject: "$stations" },
},
},
];
Model.aggregate(aggregation)
.then(function (res) {
console.log(res);
resolve(res);
})
.catch(function (err) {
reject(err);
});
Data I'm receiving in an array. What I need it the data to return only the result of the pipeline in the object, not the object inside the topmost array. How can I return the result in a way so that only the first object of the array is returned, as all that the aggregation is going to return is only a single object.
[
{
"online": [
{
"_id": "5f213786d0cdd10c61969fc7",
"stationStatus": "Online",
"connectors": [
{
"_id": "5f213786d0cdd10c61969fc8",
...
},
{
"_id": "5f213791d0cdd10c61969fcf",
...
},
{
"_id": "5f213791d0cdd10c61969fd1",
...
}
],
"metadata": {
"SerialNumber": "BP001",
"imsi": "082943327103528941"
},
"boxIdentity": "BP001"
},
{
"_id": "5f2809d7b03827069d3b5627",
"stationStatus": "Online",
"connectors": [
{
"_id": "5f213786d0ccc310c61969fc8",
...
},
{
"_id": "5f213791d0cd340c61969fcf",
...
},
{
"_id": "5f213791d0cdd10c61369fd1",
...
}
],
"metadata": {
"SerialNumber": "BP002",
"imsi": "0963433223503528941"
},
"boxIdentity": "BP002"
}
]
}
]
Aggregate will always return an array.
You could destructure the value if your using es6.
Model.aggregate(aggregation)
.then(function ([theObjectYouWant]) {
console.log(theObjectYouWant);
....

Mongoose - Search an array and return the matched results

I am looking for a way to return matched items under an array in Mongo (mongoose).
The data structure is like this:
[
{
"_id": {
"$oid": "123456"
},
"make": "Lamborghini",
"makeLogo": "/images/makeLogos/lamborghini.png",
"models": [
{
"model": "Aventador",
"_id": {
"$oid": "678909t"
}
},
{
"model": "Countach",
"_id": {
"$oid": "678909"
}
}
],
"__v": 0
},
{
"_id": {
"$oid": "2345678i90"
},
"make": "Nissan",
"makeLogo": "/images/makeLogos/nissan.png",
"models": [
{
"model": "350z",
"_id": {
"$oid": "678909gggg"
}
},
{
"model": "370z",
"_id": {
"$oid": "678909rrrrr"
}
}
],
"__v": 0
}
]
I would like to search: 3 and it should return 350z and 370z to me.
I tried the below:
modelsModel.find(
{"models.model": { $regex: req.query.carModel + '.*', $options:'i'}},
)
.exec(function(err, models) {
if(err){
res.status(400).json({error: err});
} else {
res.status(200).json({cars: models});
}
});
Where the data returned is this:
[
{ _id: 5ca893b7587ab519613b806e,
make: 'Lamborghini',
makeLogo: '/images/makeLogos/lamborghini.png',
__v: 0,
models: [
[Object], [Object]
]
}
]
This is when I searched for Countach which has a match.
I know I am doing something very obviously wrong here but this is so new to me I don't even know where to begin.
Thanks in advance!
You can use below aggregation with mongodb 4.2
db.collection.aggregate([
{ "$match": {
"models.model": { "$regex": "A" }
}},
{ "$project": {
"models": {
"$filter": {
"input": "$models",
"cond": {
"$regexMatch": {
"input": "$$this.model",
"regex": "A"
}
}
}
}
}}
])

using $elemMatch in projection with field choosing

I'm trying to select only some fields in document while also using $elemmatch. It turned out the field selection is getting ignored.
Given a document like this:
{
"author": "Robin Sharma",
"data": [
{
"translation": "en",
"content": "foo",
"unwanted_content": "huyu1",
},
{
"translation": "id",
"content": "bar",
"unwanted_content": "huyu2",
{
],
}
I'm using find() with this projection config:
const projection = {
author: 1,
data: {
$elemMatch: {
translation: "en"
},
},
}
Expected
{
"author": "Robin Sharma",
"data": [
{
"translation": "en",
"content": "foo"
},
],
}
Actual
{
"author": "Robin Sharma",
"data": [
{
"translation": "en",
"content": "foo",
"unwanted_content": "huyu1",
},
],
}
I'm still not sure how to get rid of the "unwanted_content" field.
You can achieve your required result using aggregate as:
db.collection.aggregate([
{
$unwind: "$data"
},
{
$match: {
"data.translation": "en"
}
},
{
$group: {
_id: "$author",
data: {
$push: {
translation: "$data.translation",
content: "$data.content"
}
}
}
}
])
I think you can do something like this to get only selected fields from subdocument.
db.collection.find({"data.translation": "en"},{author: 1, "data.content": 1, "data.translation": 1})

Return only matching subdocument from array of subdocuments

I'm trying to return only the subdocument that has a matching e-mail. I've done what the documentation says here, I believe. Here's what I'm trying:
function lookupReferral(email) {
return getConnection().then(db => db.collection('Referrals').findOne(
{
emails: {$elemMatch: {name: email}}
},
{
"emails.$": 1
}
));
}
Here's an example of a document (I cut down the emails array for brevity):
{
"_id": {
"$oid": "5b65979d84b8942e04f4e346"
},
"accountCode": "auth0|5b4de18d8bed60110409ded5",
"accountEmail": "abc#gmail.com",
"emails": [
{
"name": "a#ddd.dpp",
"signedUp": false,
"updated": {
"$date": "2018-08-04T12:10:05.752Z"
}
},
{
"name": "a#ddd.dpp",
"signedUp": false,
"updated": {
"$date": "2018-08-04T12:10:05.752Z"
}
}
],
"created": {
"$date": "2018-08-04T12:10:05.985Z"
},
"updated": {
"$date": "2018-08-04T12:10:05.985Z"
}
For some reason it returns null (meaning it doesn't exists I guess?), but if I remove what I specifically want, then I get the entire document returned.
You can try this
db.collection.find({
emails: {
$elemMatch: {
name: "a#ddd.dpp"
}
}
},
{
emails: {
$elemMatch: {
name: "a#ddd.dpp"
}
}
})
See the example

findOneAndUpdate property in array of objects

I'm trying to update a property in an array of objects - the find part already works. signedUp should be set to true.
Here's my method:
function lookupReferral(email) {
return getConnection().then(db => db.collection('Referrals').findOneAndUpdate(
{
emails: {$elemMatch: {name: email}}
},
{
$set: {
emails: {$elemMatch: {signedUp: true}},
updated: new Date()
}
}));
}
My idea in the $set clause is that I specify the particular object once again, and then the property that I'm setting, but it doesn't work. For further context, here's the record:
{
"_id": {
"$oid": "5b60504420f8e626148494e4"
},
"accountCode": "auth0|5b4de18d8bed60110409ded5",
"accountEmail": "example#gmail.com",
"emails": [
{
"name": "azzz#zzz.dk",
"signedUp": false
},
{
"name": "ds#d.dk",
"signedUp": false
},
{
"name": "ds#d.dk",
"signedUp": false
},
{
"name": "ds#d.dk",
"signedUp": false
}
],
"created": {
"$date": "2018-07-31T12:04:20.625Z"
},
"updated": {
"$date": "2018-07-31T12:04:20.625Z"
}
}
You need to use $ positional operator to update an array element
db.collection('Referrals').findOneAndUpdate(
{ "emails": { "$elemMatch": { "name": email }}},
{ "$set": { "emails.$.signedUp": true, "emails.$.updated": new Date() }}
)