Update many documents in MongoDB (new Schema) - mongodb

I need some help with mongo client commands, i have to update every document in collection, this is my new ProductSchema:
const ProductSchema = Schema({
name: { type: String, default: ''},
price: { type: Number, default: 0 },
image: { type: [String], default: [] },
category: { type: String, default: '' },
});
module.exports = mongoose.model('Product', ProductSchema);
The old ProductSchema has as default Product.image = null. So i have a lot of products this way stored in DB. How can i update every document in my DB Collection if Product.image == null ? and then assign it an empty array (Product.image = []). Thanks in advance.

You only need to execute update query. As docs explain method allows three fields:
query: The selection criteria for the update.
update: The modifications to apply.
options: Like multi, upsert or whatever...
So, if you want to update only values where image = null you need to query only elements where: image: null and then do the update: image: [].
Using mongo you have to add multi: true in options to update all values and not only the first who match.
So the query is like this:
db.collection.update({
"image": null
},
{
"$set": {
image: []
}
},
{
multi: true
})
Example here
Also, if you are using mongoose you can call directly updateMany() and then you don't need multi: true option.

Related

Documents inserted without schema not being found with schema

I have two new collections in MongoDB of data that I pulled from an old Firestore database that I'm moving to mongo. Since the total number between these two collections is roughly 20,000, I opted to paste the raw JSON into the insert document section in mongo, which worked like a charm and I didn't have to write a new insert route to do the same.
I then created a schema in Mongoose that matched the inserted documents, and tried to use the schema to pull back some data, and its always returning nothing.
An example of a ticket inserted via JSON:
{
"title": "How to add and manage users for your company in QuickBooks Online",
"priority": "1",
"type": "Video",
"course": "G205",
"transcriptId": "07dom27Zz98jakvB1oh5",
"status": "In Review",
"tags": "",
"url": "",
"revisionNumber": 0,
"directoryId": 19,
"checkedOut": false
},
And my schema I made to match. The collection name in mongo is also called oldTickets, the plural of my schema name here:
const mongoose = require('mongoose');
var Schema = mongoose.Schema
const schema = new Schema({
course: { type: String },
title: { type: String },
priority: { type: String },
type: { type: String },
course: { type: String },
transcriptId: { type: String },
status: { type: String },
tags: { type: String },
url: { type: String },
revisionNumber: { type: Number },
directoryId: { type: Number },
checkedOut: { type: Boolean },
});
module.exports = mongoose.model('oldTicket', schema);
And finally my model import and fetch call:
const OldTicket = require('./models/model_old_ticket');
/***************************************************************************
* Get Old Tickets - Returns all old tickets, 10 at a time
****************************************************************************/
app.get('/getOldTickets/:offset', (req, res) => {
checkConnection();
OldTicket.find().skip(parseInt(req.params.offset)).limit(10).exec((err, data) => {
if (err){ res.status(500).send({err: err}); }
//If we got data, count the tickets & return the tickets & count
if (data) {
OldTicket.find().countDocuments().then(count => {
return res.status(200).send({
tickets: data,
count: count
})
})
}
});
});
Why isn't this finding anything? Both the count and the tickets are 0. I've run into this issue before when manually creating a collection without a schema, and in those instances I would simply delete the collection, write a route to create a document, and then things would work fine. But with the large data size of these two collections, I'd rather not do that since everything should be working as is.
Edit: Example of document in Mongo
And the name of the collection I'm currently viewing:
And I just now realized that for some reason there are now two collection names, oldTickets, which has data, and oldtickets, which is empty. I'm assuming my query is searching through the empty one? How can I get it to go to the one that actually has data?
can you attach the screenshot of your data with the collection? might be it's different.in mongoose, every collection name is complete with 's'. please verify your collection is created manually by you then it has to same as mongoose schema and also completed with 's'.
example:
const mongoose = require("mongoose");
const schema = new mongoose.Schema(
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
index: true
},
filmId: {
type: mongoose.Schema.Types.ObjectId,
index: true
},
filmType: {
type: String,
index: true
},
birthday: {
type: Date
},
age: {
type: Number
},
terms: {
type: Boolean
}
},
{
versionKey: false,
timestamps: true,
}
);
schema.index({ filmId: 1, user: 1 })
module.exports = mongoose.model("UserAgeVerification", schema);
see my database

How to increment a field inside the array of documents in mongo Db?

I want to increment the quantity field inside the products array of the cart when the productId matches to the itemid. Also I want to get the updated document in return.
Here is my Cart Model
import mongoose from 'mongoose';
const cartSchema = new mongoose.Schema({
userId: {
type: String,
required: true,
},
products: [
{
productId: {
type: String,
},
quantity: {
type: Number,
default: 1
}
}
]
}, {timestamps: true});
const Cart = new mongoose.model('Cart', cartSchema);
export default Cart;
and here is what I m doing:
const updatedCart = await Cart.findOneAndUpdate({"products.productId": itemid}, {$inc: {quantity: 1}}, {new: true})
//console.log(updatedCart)
But an empty array return and also quantity didn't increment.
As from your schema, there is no quantity field. Hence your mongoose operation is not updating any document.
Hence it will not return any document as new: true only returns the updated document.
[options.returnOriginal=null] «Boolean» An alias for the new option. returnOriginal: false is equivalent to new: true.
You can use positional $ operator to update the quantity of filtered product in products array.
The positional $ operator identifies an element in an array to update without explicitly specifying the position of the element in the array.
const updatedCart = await Cart.findOneAndUpdate({ "products.productId": itemid },
{ $inc: { "products.$.quantity": 1 } },
{ new: true });
Sample Mongo Playground

How to use setDefaultsOnInsert properly

Am trying to upsert an object with a query below:
await Property.findOneAndUpdate({ "property_id": property_id }, object,{ upsert: true, setDefaultsOnInsert: true })
My schema looks like below:
const mongoose = require('mongoose');
const propertySchema = new mongoose.Schema({
property_id: String,
details: {
location: {
type: {
type: String,
default: "Point"
},
coordinates: [Number],
address: String,
country: {
type: String,
default: 'USA'
},
state: {
type: String,
default: 'CA'
},
city: {
type: String,
default: 'N/A'
},
},
status: {
type: String,
enum: ['pending', 'active', 'deleted', 'suspended'],
default: 'pending'
},
}
},
{
strict: false
});
propertySchema.index({ "details.location.coordinates": "2dsphere" });
mongoose.model('Property', propertySchema);
module.exports = mongoose.model('Property');
Yet, when new objects are inserted, attributes and their default values are not inserted, what am doing wrong ?
There a big difference between MongooseDocument and Object:
on MongooseDocument you could apply any method, like $set or .save() it. So you could modify the DB value directly. (Or convert it to JSON/Object/String and lose this property)
when you are dealing with JSON or vanilla js Object you are modifying the object itself, not the DB value. So if you want to modify the DB document you should find it by object's key and update it.
When you are dealing with Model.method_name, especially with find(One)AndUpdate you should provide object type. NOT MongooseDocument or anything else. In that case you should convert DB doc toObject by this method.
Or, if you receiving DB value via any .find method, you receive MongooseDocument by default, and you should use lean() option right after your find query. If you need js-object for any findAndUpdate method later.
For example:
let mongoose_doc = await model.findByID(id) //returns mongoose doc
but
let js_object = await model.findByID(id).lean() //returns you js object

Using mongoose timestamps option does not create properties

I may be missing something obvious, but have read to docs.I had an existing collection. Using Robo3T, I dropped it. In my script, running out of Node, I have defined the schema adding timestamps option as shown below. I run my app. The collection is created. However, there are no timestamps when I view via Robo. Everything else is as I expect. The indices are created. The fields are populated.
I expected two additional properties: createdAt and updatedAt.
I am using mongoose 5.2.7.
const categorySchema = mongoose.Schema(
{
value: String,
recordName: String,
sourceId: Number,
targetId: Number,
requestParameters: Object,
magentoResponse: Object
},
{
autoIndex: true
},
{
timestamps: true
}
);
categorySchema.index({sourceId: 1}, {unique: true});
categorySchema.index({targetId: 1, recordName: 1}, {unique: true});
Oh! I was being an idiot. autoIndex and timestamps should be in the same block. I was being an idiot!
It should have been:
const categorySchema = mongoose.Schema(
{
value: String,
recordName: String,
sourceId: Number,
targetId: Number,
requestParameters: Object,
magentoResponse: Object
},
{
autoIndex: true,
timestamps: true
}
);
categorySchema.index({sourceId: 1}, {unique: true});
categorySchema.index({targetId: 1, recordName: 1}, {unique: true});
How did you re-create those records? If they did not go though mongoose (but via mongoDB client/cli) they would not have those fields. These are mongoose specific.
And are created when you create a new Model and save it:
var thingSchema = new Schema({..}, { timestamps: { createdAt: 'created_at' } });
var Thing = mongoose.model('Thing', thingSchema);
var thing = new Thing();
thing.save(); // `created_at` & `updatedAt` will be included

How to perform an upsert in Mongoose looking for an embedded document?

SocialProfileSchema = new mongoose.Schema
source:
type: String
enum: ['twitter','facebook']
lowercase: true
user_id: String
profile_url: String
primary:
type: Boolean
default: true
added_on:
type: String
default: Math.round(new Date().getTime()/1000.0)
UserProfileSchema = new mongoose.Schema
socialProfiles: [SocialProfileSchema]
added_on:
type: String
default: Math.round(new Date().getTime()/1000.0)
That's my Schema. To check for a specific user_id within a SocialProfileSchema and then perform an upsert seems like a gargantuan task. Is it even possible?
Here's an example of how you can do an update if exists, otherwise insert:
Arguments for update are: findQuery, data, queryOptions, onComplete
var update = { data: "1", expires: 300 };
that.update({ session_id: sid }, { $set: update }, { upsert: true }, function(err, data) {
callback.apply(this, arguments);
});
How about a dbref? It will let you access the SocialProfiles directly instead of having to loop through a bunch of embedded objects
http://mongoosejs.com/docs/populate.html