Data is not updating to collection as required - mongodb

Iam trying to update my data using mongodb query in my nestjs project. But the data is not updating as required.
let school = await this.schoolModel.updateOne({ id: item.school, "exams.id": exam.id }, {
$set: {
"exams.$.terms": item.terms, "exams.$.exam": exam.id,
"exams.$.subject": item.subject
}
})

Related

How to insert bulk data one db to another db?

I am new to MongoDB. I want to copy some old data from one database to another new database.
I wrote a script that works, but I want to same change in my old data.
Present my data format is:
user {
_id: 1,
username: "jon",
email: "jon#gmail.com"
}
But I want this format:
user {
_id: "621721aed6d2481c999429e5",
username: "jon",
email: "jon#gmail.com",
old_id: 1
}
My script is:
var bulk = db.getSiblingDB("blog-new")["users"].initializeUnorderedBulkOp();
db.getCollection("users").find().forEach(function (d) {
bulk.insert(d);
});
bulk.execute();
How can I solve this issue?
Update
solve this issue using this script-
var bulk = db.getSiblingDB("user-new")["users"].initializeUnorderedBulkOp();
db.getCollection("users").find().forEach(function (d) {
d.old_id = NumberInt(d._id)
d._id = ObjectId()
print("user", d);
bulk.insert(d);
});
bulk.execute();

How to pass data for sync function using watermelondb

Good day everyone, I am working with watermelondb and I have the code below, but I don't know how to actually use it. I am new in watermelondb and I don't know how to pass data as props to the pullChanges and pushChanges objects. How do I pass necessary data like changes and lastPulledAt from the database into the sync function when I call it. And I need more explanation on the migrationsEnabledAtVersion: 1 too. Thanks in advance for your gracious answers.
import { synchronize } from '#nozbe/watermelondb/sync'
async function mySync() {
await synchronize({
database,
pullChanges: async ({ lastPulledAt, schemaVersion, migration }) => {
const urlParams = `last_pulled_at=${lastPulledAt}&schema_version=${schemaVersion}&migration=${encodeURIComponent(JSON.stringify(migration))}`
const response = await fetch(`https://my.backend/sync?${urlParams}`)
if (!response.ok) {
throw new Error(await response.text())
}
const { changes, timestamp } = await response.json()
return { changes, timestamp }
},
pushChanges: async ({ changes, lastPulledAt }) => {
const response = await fetch(`https://my.backend/sync?last_pulled_at=${lastPulledAt}`, {
method: 'POST',
body: JSON.stringify(changes)
})
if (!response.ok) {
throw new Error(await response.text())
}
},
migrationsEnabledAtVersion: 1,
})
}
Watermelondb's documentation is terrible and its link to typescript even worse.
I spent almost a week to get 100% synchronization with a simple table, now I'm having the same problems to solve the synchronization with associations.
Well, the object you need to return in pullChanges is of the following form:
return {
changes: {
//person is the name of the table in the models
person: {
created: [
{
// in created you need to send null in the id, if you don't send the id it doesn't work
id: null,
// other fields of your schema, not model
}
],
updated: [
{
// the fields of your schema, not model
}
],
deleted: [
// is a string[] consisting of the watermelondb id of the records that were deleted in the remote database
],
}
},
timestamp: new Date().getTime() / 1000
}
In my case, the remote database is not a watermelondb, it's a mySQL, and I don't have an endpoint in my API that returns everything in the watermelon format. For each table I do a search with deletedAt, updatedAt or createdAt > lastPulledAt and do the necessary filtering and preparations so that the data from the remote database is in the schema format of the local database.
In pushChanges I do the reverse data preparation process by calling the appropriate creation, update or deletion endpoints for each of the tables.
It's costly and annoying to do, but in the end it works fine, the biggest problem is watermelon's documentation which is terrible.

Mongoose: deleteOne middleware for cascading delete not working

With remove being deprecated in Mongoose 5.7.13, I want to use deleteOne instead. I need to get the id of the deleted document so that I can then delete further related documents in other collections in a cascade. I thought that "this" within the context of the pre middleware hook was meant to refer to the removed document, but instead it's just an empty object. Is there a canonical working example of this? I'm still currently using 5.7.12 at this point - will that make a difference here?
Here is the code I'm currently working with. The issue is that I can't get the projectId at the start because the reference is completely empty. Doing this on post rather than pre, or switching the option to run on query rather than document all yield the same result.
ProjectSchema.pre("deleteOne", {document:true}, (next) => {
const projectId = this._id;
ListModel.find({parentProject:projectId}, (err, lists) => {
if(err){
console.log("error cascading project delete to lists", {err});
}
lists.map(list => {
ListModel.deleteOne({_id:list._id}, (err, result) => {
if(err) {
console.log("error on project delete cascade", {err});
}
});
});
});
});
It depends whether you call deleteOne on document or on model. The later just have no document to bind it to.
The former gives you the document as you expect:
const project = await ProjectModel.findOne();
project.deleteOne();
The later gives you the Query. There is no _id in the query, but it has this.op for example, which in this middleware will be "deleteOne":
await ProjectModel.deleteOne();
The only way to get the document id in this case is to ensure it is provided in the query:
await ProjectModel.deleteOne({_id: "alex"});
Then you can get it in the middleware from the filter:
const projectId = this.getFilter()["_id"]
You can specify query: false in second parameter of the middleware to ensure the it is not invoked when you call deleteOne on model. So the best you can do:
ProjectSchema.pre("deleteOne", {document:true, query: false}, (next) => {
const projectId = this._id;
....
});
ProjectSchema.pre("deleteOne", {document:false, query: true}, (next) => {
const projectId = this.getFilter()["_id"];
if (typeof projectId === "undefined") {
// no way to make cascade deletion since there is no _id
// in the delete query
// I would throw an exception, but it's up to you how to deal with it
// to ensure data integrity
}
});
Please take a look at corresponding tests on v5.7.12: https://github.com/Automattic/mongoose/blob/5.7.12/test/model.middleware.test.js#L436
In the mongoose docs it says "Model.deleteOne() does not trigger pre('remove') or post('remove') hooks."
There is solution if you can refactor your delete operations with findByIdAndDelete, it triggers the findOneAndDelete middleware,
So we can add this middleware to Project Schema.
Project model:
const mongoose = require("mongoose");
const ProjectChild = require("./projectChild");
const ProjectSchema = new mongoose.Schema({
name: String
});
ProjectSchema.post("findOneAndDelete", async function(doc) {
console.log(doc);
if (doc) {
const deleteResult = await ProjectChild.deleteMany({
parentProject: doc._id
});
console.log("Child delete result: ", deleteResult);
}
});
module.exports = mongoose.model("Project", ProjectSchema);
ProjectChild model:
const mongoose = require("mongoose");
const projectChildSchema = new mongoose.Schema({
name: String,
parentProject: {
type: mongoose.Schema.Types.ObjectId,
ref: "Project"
}
});
module.exports = mongoose.model("ProjectChild", projectChildSchema);
I created a project like this:
{
"_id": "5dea699cb10c442260245abf",
"name": "Project 1",
"__v": 0
}
And created 2 project child for this project:
Child 1
{
"_id": "5dea69c7b10c442260245ac0",
"name": "Child 1 (project 1)",
"parentProject": "5dea699cb10c442260245abf",
"__v": 0
}
Child 2
{
"_id": "5dea69e8b10c442260245ac1",
"name": "Child 2 (project 1)",
"parentProject": "5dea699cb10c442260245abf",
"__v": 0
}
I created a sample route to delete a project by its id like this:
router.delete("/project/:id", async (req, res) => {
const result = await Project.findByIdAndDelete(req.params.id);
res.send(result);
});
When I send a DELETE request to this route, we see the following info in the console:
console.log(doc);
{ _id: 5dea699cb10c442260245abf, name: 'Project 1', __v: 0 }
console.log("Child delete result: ", deleteResult);
Child delete result: { n: 2, ok: 1, deletedCount: 2 }
So we could deleted the 2 children of the project, when we deleted the project.
As an alternative you can also use findOneAndRemove, it triggers findOneAndRemove post middleware.
So in the ProjectSchema we replace the post middleware like this:
ProjectSchema.post("findOneAndRemove", async function(doc) {
console.log(doc);
if (doc) {
const deleteResult = await ProjectChild.deleteMany({
parentProject: doc._id
});
console.log("Child delete result: ", deleteResult);
}
});
When we use a findOneAndRemove operation, the result will be the same as the first alternative:
const result = await Project.findOneAndRemove({ _id: req.params.id });

Circular Reference Issue in Mongoose pre-hook

In my MongoDB/Node backend environment I am using Mongoose pre and post hook middleware to check what's changed on the document, in order to create some system notes as a result.
One problem I'm running into is that when I try and lookup the record for the document in question I get a "Customer.findOne()" is not a function error. This is ONLY a problem when I'm looking up a record from the same collection from which the model just launched this pre and post hook triggers file. In other words, if my "Customer" model kicks off functions in a pre hook function in an external file, then I get an error if I then try and lookup a Customer with a standard findOne():
My customer model looks something like this:
module.exports = mongoose.model(
"Customer",
mongoose
.Schema(
{
__v: {
type: Number,
select: false
},
deleted: {
type: Boolean,
default: false
},
// Other props
searchResults: [
{
matchKey: String,
matchValue: String
}
]
},
{
timestamps: true
}
)
.pre("save", function(next) {
const doc = this;
trigger.preSave(doc);
next();
})
.post("save", function(doc) {
trigger.postSave(doc);
})
.post("update", function(doc) {
trigger.postSave(doc);
})
.post("findOneAndUpdate", function(doc) {
trigger.postSave(doc);
})
);
... the problematic findOne() function in the triggers file being called from the model looks like this:
const Customer = require("../../models/customer");
exports.preSave = async function(doc) {
this.preSaveDoc = await Customer.findOne({
_id: doc._id
}).exec();
};
To clarify, this is NOT a problem if I'm using a findOne() to lookup a record from a different collection in this same triggers file. Then it works fine. See below when finding a Contact -- no problem here:
const Contact = require("../../models/contact");
exports.preSave = async function(doc) {
this.preSaveDoc = await Contact.findOne({
_id: doc._id
}).exec();
};
The workaround I've found is to use Mongo instead of Mongoose, like so:
exports.preSave = async function(doc) {
let MongoClient = await require("../../config/database")();
let db = MongoClient.connection.db;
db.collection("customers")
.findOne({ _id: doc._id })
.then(doc => {
this.preSaveDoc = doc;
});
}
... but I'd prefer to use Mongoose syntax here. How can I use a findOne() in a pre-hook function being called from the same model/collection as the lookup type?
I have ran similar issue few days ago.
Effectively it is a circular dependency problem. When you call .findOne() on your customer model it doesn't exist as it is not exported yet.
You should probably try something like that :
const customerSchema = mongoose.Schema(...);
customerSchema.pre("save", async function(next) {
const customer = await Customer.findOne({
_id: this._id
}).exec();
trigger.setPreSaveDoc(customer);
next();
})
const Customer = mongoose.model("Customer", customerSchema)
module.export Customer;
Here customer will be defined because it is not called (the pre hook) before its creation.
As an easier way (I am not sure about it) but you could try to move the Contact import in your Trigger file under the save function export. That way I think the decencies may works.
Did it helps ?

mongodb update failes on express session

I am using passportjs for authentication. I am using mongodb to store express sessions. The document that gets saved contains 3 fields _id, session, expires.
When I try to update the document using mongoose it does not. It does however find the document but does not update.
Would there be any lock on the document? When I try to update from mongo console it does...
Please help.
here is my code:
var conditions = { '_id' : req.sessionID};
var update = { $set: { 'ip': '111.11.111.1112' }};
Sessions.update(conditions, update, function (err, res) {
if (err) return callback("FAILED");
return callback("SUCCESS");
});
This is my schema.....
var mongoose = require('mongoose');
// define the schema for our user model
var sessionsSchema = mongoose.Schema({
_id : String,
session : String,
ip : String,
expires : String
});
// create the model for users and expose it to our app
module.exports = mongoose.model('sessionsIP', sessionsSchema, 'sessionsIP');