Remove object fields by updating the complete object - javascript

This is some data which is stored in a mongoDB document:
{
_id: "123"
order: 1
parent: "Dueqmd64nTxM3u9Cm"
type: "article"
unit: "kg"
}
While all the saved data will be calculated and validated first (that's why I don't use only data = { order: 2 }), I'm using the complete object to update the document:
var data = {
order: 2
parent: "Dueqmd64nTxM3u9Cm"
type: "article"
unit: "kg"
}
Collection.update(
{ _id: 123 },
{ $set: data }
);
This is working.
But if I want to remove some values, it doesn't work:
var data = {
order: 2
parent: "Dueqmd64nTxM3u9Cm"
type: "article"
unit: undefined
}
Collection.update(
{ _id: 123 },
{ $set: data }
);
I'm expecting the unit-field to get removed. But that isn't the case...

To remove fields, use the $unset operator:
data = {
unit: ""
};
Collection.update(
{ _id: 123 },
{ $set: data }
);

Related

How to find document's array item by its "_id" field in MongoDB (Mongoose)?

I have the following schema (NestJS + Mongoose):
#Schema({ timestamps: true })
export class Listing {
#Prop({
type: [{
bidderId: { type: Types.ObjectId, required: true, select: false, ref: User.name, index: true },
amount: { type: Number, required: true },
date: { type: Date, required: true }
}],
select: false
})
bids!: Bid[]
}
so basically every listing document has an array of bids.
now I notice that automatically mongoDB (or mongoose) creates _id field for every bid item I put into the bids array.
My question is, If I have a bid's _id, how can I query it's item from the listing's bids array? something like:
// Adding a new bid to the listing, and retrieving the updated listing
const listingWithAddedBid = await this.listingModel.findByIdAndUpdate(listingId, {
$push: {
bids: {
$each: [{
amount: bidInfo.amount,
bidderId: new Types.ObjectId(user.id),
date: new Date()
}],
$sort: { amount: -1 }
}
}
}, { new: true })
// Getting the new bid's _id from the array (it will be at index 0 because we sort buy amount)
const newBidId = listingWithAddedBid.bids[0]._id
// here how can I query the entire bid item from the array with 'newBidId'? this won't work
this.listingModel.findById(newBidId) // returns null
https://docs.mongodb.com/manual/tutorial/query-array-of-documents/
https://docs.mongodb.com/manual/indexes/#default-_id-index
this.listingModel.findOne({ "bids._id": newBidId, {}, {}, (error, doc) =>
{
if (error) {
....
}
if (doc) {
....
} else {
...//'Not Found';
}
});

how to count records in mongodb

I am new in mongodb.
i have a simple email Schema which implemented like below :
const emailSchema = new Schema({
from:{
type: String
},
to: {
type: String
},
subject: {
type: String
},
content: {
type: String
},
provider:{
type: String
},
success:{
type: Boolean
}
now i want to query all email records and seprate them in two array. one for provider=x and provider = y . then count each one's success field.
how can i write such query ?
If you only want to count success: true for any provider
emailSchema.aggregate([{
$match: {
{ 'success': true }
},
$group: {
_id: {
provider: '$provider'
}, //group by provider
count: {
$sum: 1
}
} //sum of success fields
]);
If you only want to count success field exists or not it may be true or false for any provider
emailSchema.aggregate([{
$match: {
{'success': { $exists: true }}
},
$group: {
_id: {
provider: '$provider'
}, //group by provider
count: {
$sum: 1
}
} //sum of success fields
]);
Use aggregate query for group and count
emailSchema.aggregate([{
$group: {
_id: {
provider: '$provider'
}, //group by provider
count: {
$sum: '$success'
}
} //sum of success fields
])

MongoDB: Merge of two update requests possible?

Do I have to do two updates, if I want to unset one value and set another value? Or is it possible to merge both together?
Collection.update(
{ _id: id },
{ $unset: { 'status.editing': '' } }
);
Collection.update(
{ _id: id },
{ $set: { 'status.version': timestamp } }
);
How about
Collection.update(
{ _id: id },
{
$unset: { 'status.editing': '' },
$set: { 'status.version': timestamp }
}
);
See $unset and $set
It is also possible to set or unset multiple fields at the time with
{ $unset: { quantity: "", instock: "" } }
or
{ $set:
{
quantity: 500,
details: { model: "14Q3", make: "xyz" },
tags: [ "coats", "outerwear", "clothing" ]
}
}

Calculating average inside a Mongoose hook

I want to calculate an average every time a new element is added to a collection. Basically, what I'm trying to calculate is inside a "pre save" hook, but I'm always getting undefined results.
This is the schema:
var CommentSchema = new Schema({
posted:{
type:Date,
default:Date.now
},
text:{
type: String
},
owner:{
_id:{
type: Schema.Types.ObjectId, ref: 'User'
},
displayName:{
type:String
}
},
reference: {
objectType:{
type: String,
enum: [ 'document','element','process', 'project', 'story']
},
_id:{
type: Schema.Types.ObjectId
}
},
sentiment:{
score:{
type:Number,
default:0.0
},
comparative:{
type:Number,
default:0.0
}
}
});
CommentSchema.pre('save', function(next){
var thiz = this;
// this code is inside another callback, that's the reason I'm using thiz
if(thiz.reference.objectType ==='element'){
mongoose.models['Comment'].aggregate([
{ $match:{'reference._id': mongoose.Types.ObjectId(thiz.reference._id)} },
{ $group:{'reference._id': mongoose.Types.ObjectId(thiz.reference._id), average:{$avg:'$sentiment.score'}}}
],
function(err, result){
console.log('------------------');
console.log('result',result);
console.log('------------------');
}
);
}
next();
});
I always get undefined results, however, if I query like the example below, I get the list of comments.
db.getCollection('comments').find({"reference._id":ObjectId("55a69276242aa1837a1ecb6c")})
Is there anything I am missing in the aggregate?
{ $group: { _id: null, average: { $avg: '$sentiment.score' } } }
"The _id field is mandatory; however, you can specify an _id value of
null to calculate accumulated values for all the input documents as a
whole."
http://docs.mongodb.org/manual/reference/operator/aggregation/group/
$group: { _id: <expression>, <field1>: { <accumulator1> : <expression1> }, ... } }

MongoDb's $ (update) does not update array's element but rather replace it?

I want to update an element of an array inside mongodb's document (I am using mongoose). Schema is something like:
{
..
arr : [{
foo: Number,
bar: [String],
name: String
}]
..
}
And my query is:
SomeModel.update({
_id: "id of the document",
arr: {
$elemMatch: {
_id: "_id assigned by mongoose to array element"
}
}
}, {
'arr.$': {
name: 'new name'
}
}).exec()
It just replaces whole array element say:
{
_id: "some objectId",
name: 'old name',
foo: 0,
}
to:
{
name: 'new name'
}
what I want:
{
_id: "some objectId",
name: 'new name',
foo: 0,
}
What I am curious to know if it is possible to achieve this in single update query ? (May be there is a silly mistake in my query :P or another approach)
I would also like to do update query like so:
{
$inc: { foo: 1},
$push: { bar: "abc"}
}
If you are still struggling with the whole implementation the full application of your statement is as follows:
SomeModel.update(
{
"arr._id": "123"
},
{
"$set": { "arr.$.name": "new name" },
"$inc": { "arr.$.foo": 1},
"$push": { "arr.$.bar": "abc" }
}
)
,function(err,numAffected) {
});
So each operation is performed in turn.

Categories