mongodb - how to project last element of an array after an update - mongodb

So I have the following query:
ListModel
.findOneAndUpdate(
{
_id: list_id
},
{
$push: {
"items": {
details: the_template
}
}
},
{
new: true,
projection: {
items: 1
}
}
)
So, this returns me the array of the updated document, but how would I get only the last element inserted?

You can use of $slice, in your case :
ListModel
.findOneAndUpdate(
{
_id: list_id,
},
{
$push: {
items: {
details: the_template,
},
},
},
{
new: true,
projection: {
items: {
$slice: -1,
},
},
},
);

Related

Finding nested array objects with mongoose

I have a user collection like this
{
"_id": {
"$oid": "62fe22f5d37c317701922d66"
},
"name": "Fahim Faisal",
"email": "fahim.faisal.abir#gmail.cc",
"password": "$2a$12$bkjeD.GesX4f7BNVF7C0CuKkkTyQA19kv6SAWuhObmPlAB11Tz9dy",
"notes": [],
"folders": [
{
"_id": {
"$oid": "62fe22f5d37c317701922d67"
},
"name": "My Notes",
"notes": []
},
{
"_id": {
"$oid": "62fe22f5d37c317701922d68"
},
"name": "Todos",
"notes": []
},
],
"__v": 0
}
I want to check if an exact item in folders exists or not.
What I have tried so far
User.findOne(
{ _id: req.userId },
{
folders: {
$elemMatch: {
_id,
},
},
},
(err, system) => {
if (err) {
console.log(err);
} else {
console.log(system);
}
}
);
It doesn't return the exact item. It returns this
{
_id: new ObjectId("62faf0c424411076eb9b80e6"),
folders: [
{
_id: new ObjectId("6302110a230f9123c1110273"),
name: 'My Notes',
notes: []
},
{
_id: new ObjectId("6302110a230f9123c1110274"),
name: 'Todos',
notes: []
},
{
_id: new ObjectId("6302110a230f9123c1110275"),
name: 'Projects',
notes: []
},
{
_id: new ObjectId("6302110a230f9123c1110276"),
name: 'Journals',
notes: []
},
{
_id: new ObjectId("6302110a230f9123c1110277"),
name: 'Reading list',
notes: []
}
]
}
What should I do to get the exact item in the folders array exists or not?
Add the $elemMatch filter for folders in the first object parameter, and with $ (projection) to limit and return the first (matched) item of folders array.
Assume that i_d is ObjectId type.
User.findOne(
{
_id: req.userId,
folders: {
$elemMatch: {
_id: _id
}
}
},
{
"folders.$": 1
},
(err, system) => {
if (err) {
console.log(err);
} else {
console.log(system);
}
}
);
Demo # MongoPlayground
You should specify an Id in the elemMatch. For example something like this
User.findOne(
{ _id: req.userId },
{
folders: {
$elemMatch: {
_id:ObjectId('String Id'),
},
},
},
(err, system) => {
if (err) {
console.log(err);
} else {
console.log(system);
}
}
);

mongoDB: update nested array element

I have the following datastructure
{
_id: ObjectId('61ae12bfb8047effd0ac2a01'),
data: [
{
xml: {
messageId: 1638798015073,
xmlString: 'someXML'
},
data: [
{
customerId: 123456,
validation: {
isValid: true,
message: ''
},
docs: [
{
objectId: 'PA1106:zt:bb302216879669b58c141b12dcdd5eb0',
writtenBack: false
}
]
},
{
customerId: 55555,
validation: {
isValid: true,
message: ''
},
docs: [
{
objectId: 'PA1106:zt:bb302216879669b58b143ef38c016217',
writtenBack: true
}
]
}
]
},
{
xml: {
messageId: 1638798015094,
xmlString: 'someXML'
},
data: [
{
customerId: 55555,
validation: {
isValid: true,
message: ''
},
docs: [
{
objectId: 'PA1106:zt:bb302216879669b58c1416129062c2d2',
writtenBack: false
},
{
objectId: 'PA1106:zt:b8be9ea04011c2a18c148a0d4c9d6aab',
writtenBack: true
}
]
},
]
},
],
createdAt: '2021-12-06T13:40:15.096Z',
createdBy: 'Test'
}
Now I want to update the writtenBack property of for a given Document and objectId. How would I write a query for this?
my updateOne looked like this
{
_id: '61ae12bfb8047effd0ac2a01',
'data.data.docs.objectId': 'PA1106:zt:bb302216879669b58b143ef38c016217'
},
{
$set: { 'data.data.docs.$.writtenBack': true }
}
I know there is arrayFilters for nested arrays, but as far as I know, I need a unique identifier for each array-Level. But I only have the objectId which is unique for a Document. Any Ideas?
Yes, you can achieve the update for the document in the nested array with positional operator $[] and arrayFilters.
db.collection.update({
_id: "61ae12bfb8047effd0ac2a01",
},
{
$set: {
"data.$.data.docs.$[doc].writtenBack": true
}
},
{
arrayFilters: [
{
"doc.objectId": "PA1106:zt:bb302216879669b58b143ef38c016217"
}
]
})
Sample Mongo Playground
I made it work with this query
{
_id: '61ae12bfb8047effd0ac2a01',
},
{
$set: { 'data.$[elem1].data.$[elem2].docs.$[elem3].writtenBack': true }
},
{
arrayFilters: [
{ 'elem1.xml.messageId': 1638798015094 },
{ 'elem2.customerId': 55555},
{ 'elem3.objectId': 'PA1106:zt:bb302216879669b58c1416129062c2d2'}]
}

mongodb $pull in array with another array

Help me please to remove elements in an array with such document schema:
contracts: [
{
bandwidth: {
calculated: {
value: Number,
documents: [id1, id2, id3, id4],
}
}
}
]
I want to delete elements in all documents array that are in filter array.
I tried:
const documentsToDelete = [id2, id3]
const points = await Point.updateMany({
$pull: {
contracts: {"bandwidth.calculated.documents": {$in: documentsToDelete}}
},
});
But it does not work. The resulting array must contain "id1" and "id4"
Correct the things,
the first parameter is the query part to match the condition
the contracts is an array so use $[] to update operation in all elements
const documentsToDelete = [id2, id3];
const points = await Point.updateMany(
{},
{
$pull: {
"contracts.$[].bandwidth.calculated.documents": {
$in: documentsToDelete
}
}
}
)
Playground
bellow quires worked for me well
let feed = await Feed.findOneAndUpdate(
{
_id: req.params.id,
feeds: {
$elemMatch: {
type: FeedType.Post,
locations: {
$elemMatch: {
uniqueName,
},
},
},
},
},
{
$pull: {
//#ts-ignore
'feeds.$[].locations': { uniqueName },
},
},
{ new: true }
);
or
let feed = await Feed.findOneAndUpdate(
{
$and: [
{
_id: req.params.id,
},
{
'feeds.$[].locations': {
$elemMatch: {
uniqueName,
},
},
},
],
},
{
$pull: {
//#ts-ignore
'feeds.$[].locations': { uniqueName },
},
},
{ new: true }
);

How to Combine GeoQuery with another separate query in MongoDB and paginate result?

let params = {
$or: [
{//STATUS1 PERSON
status: { '$in': ['Status1'] }, object: { '$in': ['Person'] },
geometry: {
$near: {
$maxDistance: 160000,
$geometry: {
type: "Point",
coordinates: [geoCoordinates[1], geoCoordinates[0]]
}
}
},
name: { '$in': req.user.names },
sessionStartTime: { "$gte": new Date() },
$and: [
{
user_id: '',
},
{
userID: { $exists: false }
}
]
},
{ //STATUS1 ALL OTHER ITEM TYPES
status: { '$in': ['Status1'] }, object: { '$in': ['Animal', 'Planet', 'Star'] },
name: { '$in': req.user.names },
sessionStartTime: { "$gte": new Date() },
$and: [
{
user_id: '',
},
{
userID: { $exists: false }
}
]
},
{ //ALL ITEM TYPES WITH STATUS2 AND STATUS3
status: { '$in': ['Status2', 'Status3'] }, object: { '$in': ['Person', 'Animal', 'Planet', 'Star'] },
user_id: req.user._id
}
]
}
var options = {
page: 1,
limit: 5
};
let foundItems = await User.paginate(params, options).then(function (result) {
});
With this query, I'm getting the following error:
MongoError: geoNear must be top-level expr
How do I include geometry query as one query among others and return the combined result with pagination ? Or is there a different way to achieve the same result?

MongoDB $pull from array with filter

I have User collection:
[
{
_id: '5b3935c2d4850aa2d9f0ae25',
feedBucket: [
{
_id: '2a3535c2d4852ba2d9f0ae52',
createdAt: '2018-06-30 21:52:22.681'
},
{
_id: '9f342c2d4852ba2d9f0ae52',
createdAt: '2018-06-30 21:52:22.681'
}
]
},
{
_id: '3d2343c2d4850aa2d9f0ae33',
feedBucket: [
{
_id: '2a3535c2d4852ba2d9f0ae52',
createdAt: '2018-02-30 21:52:22.681'
},
{
_id: '9f342c2d4852ba2d9f0ae52',
createdAt: '2018-06-30 21:52:22.681'
}
]
}
]
And I am trying to pull document with id - '9f342c2d4852ba2d9f0ae52' from users feedBucket.
await User.updateMany(
{},
{ $pull: { feedBucket: { _id: '9f342c2d4852ba2d9f0ae52' } } },
{ multi: true }
)
but it doesn't work, result is { n: 2, nModified: 0, ok: 1 }
If your feedBucket._id is ObjectId then you need to $pull it by converting to mongoose ObjectId
const user = await User.update(
{ },
{ $pull: { feedBucket: { _id: mongoose.Types.ObjectId('5b07fa836569d356ba5bd2fa') } } },
{ multi: true }
)