Mongo error 301 occurs when doing write operations - node.js

When doing write operations(save, delete), Mongo Error occurs on my Nodejs server. Error code is 301.
I'm using TypeORM v0.2.29 and mongodb v3.6.3 right now. The database is AWS DocumentDB.
This is simplified server code:
import { createConnections } from 'typeorm';
import { readFileSync } from 'fs';
import ObjectID from 'bson-objectid';
const [mongodb, ...] = await createConnections([
{
url: 'mongodb://<username>:<password>#docdb~~.amazonaws.com/<database>?replicaSet=rs0&readPreference=secondaryPreferred',
ssl: true,
sslValidate: true,
sslCA: [readFileSync('/path/to/ssl/ca')],
},
{...}
]);
const repository = mongodb.getMongoRepository(SomeEntity);
const entity = new SomeEntity();
entity.id = ObjectID.generate();
entity.someValue = someValue;
await repository.findOne(1); //works fine
const result = await repository.save([entity]); //MongoError occurs
Edit: Turns out id is defined before the entity is persisted. Is that could be a problem?
Edit 2: I tried on development enviornment(it took quite amount of time to set up. sorry for give you the information late), and I got Retryable writes not supported error. This is full error message:
However, no matter if I put retryWrites=false option on query string, it gives the same error.

Related

Trying to connect to my Atlas cluster with node.js driver but get "TypeError: client.close is not a function" instead

I'm a newbie on stackoverflow. I'm beginning with mongodb and node.js, following step-by-step tutorials from W3S. I succeeded in connecting to my cluster with mongosh client and performed basic CRUD operations and queries. So far, so good. My problem started when I tried to connect to my cluster from node.js. I just copy-pasted the sample code from W3S and then replaced the uri variable default string with my cluster uri. When running my node.js app, I get a "TypeError: client.close is not a function".
I'm using the last version to date of node and mongo driver.
I've tried to find an answer on stackoverflow and other community forums, but nothing that fixed my issue. I tried to connect again and again using code snippets from other tutorials, including the full driver example code provided by Atlas. I've checked my uri string over and over but did not find anything suspect. At some point, I thought the problem might come from my password encoding, so I tried the code below from MongoDB troubleshouting page. Unfortunately, it didn't change anything. What did I miss ? Any help would be greatly appreciated !
`
const { MongoClient } = require("mongodb");
const username = encodeURIComponent("<myusername>");
const password = encodeURIComponent("<mypassword>");
const cluster = "cluster0.2lulwez.mongodb.net";
let uri =
`mongodb+srv://${username}:${password}#${cluster}/?retryWrites=true&w=majority`;
const client = new MongoClient(uri);
async function run() {
try {
await client.connect();
} finally {
await client.close();
}
}
run().catch(console.dir);
`
Probably is the user, the password or the url that is wrong or your ip address is not well configured in the atlas for the connection well.
I proved and works, you can add try catch to see the error:
Replace your function run, with this:
async function run() {
try {
console.log("connecting...");
await client.connect();
console.log("connected...");
} catch (error) {
console.log(error);
} finally {
try {
console.log("closing...");
await client.close();
console.log("closed ...");
} catch (error) {
console.log(error);
}
}
}
run().catch(console.dir);
Source:
https://www.mongodb.com/docs/drivers/node/current/quick-start/

Error on items.add in pnpjs after 30minutes

I´m using "#pnp/sp": "^3.0.3", I have this code
const sp = spfi().using(SPFx(props.context));
const item = {
Title: mail,
URL: { Url: url.trim(), Description: name.trim() },
};
await sp.web.lists.getById(props.list).items.add(item);
It works, I can find the item in the list. It´s added.
If I have the page open 30 minutes and insert a new item it fails with this error
Error: Error making HttpClient request in queryable [403] ::> {"odata.error":{"code":"-2130575252, Microsoft.SharePoint.SPException","message":{"lang":"en-US","value":"The security validation for this page is invalid and might be corrupted. Please use your web browser's Back button to try your operation again."}}}
It´s going to be solved in version 3.2.0
But doesn´t work with
const sp = spfi().using(SPFx(props.context));
It does with
import { spfi, SPBrowser } from "#pnp/sp";
....
const sp = spfi().using(
SPBrowser({
baseUrl: props.context.pageContext.web.absoluteUrl,
}));

Mailchimp and Node.js with typescript noob question: Import vs Require

I am creating an app that sends certain transactional emails using Mailchimp.
They have great docs here: https://mailchimp.com/developer/api/transactional/messages/send-using-message-template/
But Im using typescript, so the line:
var mailchimp = require("mailchimp_transactional")("API_KEY");
Doesn't work, I get the following error:
Error: Cannot find module 'mailchimp_transactional'
I know this is something small, but I am not sure how to get around it at all. I found an article that describes creating your own types file here: #mailchimp/mailchimp_marketing/types.d.ts' is not a module in nodeJs
But there has to be a quicker simpler solution. It also doesn't make it clear how to set the API key in that case.
I have tried to import the module which is #mailchimp/mailchimp_transactional which did not work.
I have ofcourse also run npm install #mailchimp/mailchimp_transactional
Any help would be appreciated, here is a full sample just incase it helps.
var mailchimp = require("mailchimp_transactional")("API_KEY");
export const testSendEmailFromTemplate = async () => {
let mcbody = {
template_name: "my-template",
template_content: [{
name:"firstname",
content:"INJECTED.BY.TEMPLATE.CONT.firstname"
},
{
name:"surname",
content:"INJECTED.BY.TEMPLATE.CONT.surname"
}],
message: {
to:{
email:"email#gmail.com",
name: "Test",
type: "to"
}
},
async:true
};
return await mailchimp.messages.sendTemplate(mcbody);
}
If anyone is unfortunate enough to face this issue because Mailchip's docs don't cater to the typescript setup, and you aren't sure how to make it 'just work' here is the answer:
const mailchimpFactory = require("#mailchimp/mailchimp_transactional/src/index.js");
const mailchimp = mailchimpFactory("PUTKEYHERE");
This pulls in the javascript file directly and then the second line initialises the object.
Good luck all!
As of March 2022 the types have been added to DefinitelyTyped and can be accessed by running
npm install --save-dev #types/mailchimp__mailchimp_transactional
I had the same problem in a node/Typescript project, but this is working for me:
const mailchimp = require('#mailchimp/mailchimp_marketing')
export class MailchimpServices {
constructor() {
mailchimp.setConfig({
apiKey: '...',
server: 'us5',
});
}
async ping() {
console.log('Start mailchimp ping!')
const response = await mailchimp.ping.get();
console.log(response);
}
}

'FIRESTORE INTERNAL ASSERTION FAILED: Unexpected state' when unit testing with Jest

I'ḿ setting up a jest test suite for a Node.js and Express REST API i'm building, i'm using #firebase/testing module to initialize a testing app, however when i try to perform any sort of operation to the database this error comes out:
FIRESTORE (7.17.2) INTERNAL ASSERTION FAILED: Unexpected state
at fail (/home/cardonapablo/Documentos/Proyectos/Optica (Ilicit)../../../../../node_modules/#firebase/testing/node_modules/#firebase/firestore/src/util/assert.ts:39:9)
at hardAssert (/home/cardonapablo/Documentos/Proyectos/Optica (Ilicit)../../../../../node_modules/#firebase/testing/node_modules/#firebase/firestore/src/util/assert.ts:53:5)
at fromBytes (/home/cardonapablo/Documentos/Proyectos/Optica (Ilicit)../../../../../node_modules/#firebase/testing/node_modules/#firebase/firestore/src/remote/serializer.ts:270:5)
at fromWatchChange (/home/cardonapablo/Documentos/Proyectos/Optica (Ilicit)../../../../../node_modules/#firebase/testing/node_modules/#firebase/firestore/src/remote/serializer.ts:486:25)
at PersistentListenStream.onMessage (/home/cardonapablo/Documentos/Proyectos/Optica (Ilicit)../../../../../node_modules/#firebase/testing/node_modules/#firebase/firestore/src/remote/persistent_stream.ts:576:25)
at /home/cardonapablo/Documentos/Proyectos/Optica (Ilicit)../../../../../node_modules/#firebase/testing/node_modules/#firebase/firestore/src/remote/persistent_stream.ts:456:21
at /home/cardonapablo/Documentos/Proyectos/Optica (Ilicit)../../../../../node_modules/#firebase/testing/node_modules/#firebase/firestore/src/remote/persistent_stream.ts:509:18
at /home/cardonapablo/Documentos/Proyectos/Optica (Ilicit)../../../../../node_modules/#firebase/testing/node_modules/#firebase/firestore/src/util/async_queue.ts:369:14
I also tried connecting to my regular firestore database with the credentials i have been using to develop the endpoints and same error pops out even tho it's the app i use daily
Weird thing is, data is being written to the database, but error still stops testing
Here is firebase setup:
(src/db/functions.js)
let app = initializeTestApp({
projectId: "illicit"
})
db = app.firestore()
module.exports = { db }
Function throwing the error
(tests/fixtures/db.js)
const { db } = require('../../src/db/functions')
const bcrypt = require('bcrypt');
const createAdmin = async function() {
// Encrypt password
let encPass = await bcrypt.hash("admin", 8)
let admin = {
name: "Admin Test User",
email: "admin#test.com",
password: encPass,
tokens: []
}
// Add to db
let docRef = await db.collection('admins').add(admin) // <- This line throws the error
return;
}
module.exports = {
createAdmin
}
And finally testing file
(tests/glasses.test.js)
const supertest = require('supertest');
const app = require('../src/app')
const functions = require('./fixtures/db')
let adminToken;
let glassesId;
//Executes before any test, here is where error occurs, before any tests
beforeAll( async () => {
await functions.createAdmin()
return
})
test('Should log in an admin', async () => {
let response = await supertest(app)
.post('/admins/login')
.send({
email: 'admin#test.com',
password: 'admin'
})
.expect(200);
expect(response.body.token).toEqual(expect.any(String))
adminToken = response.token;
});
This only happens only when i try to test, regular app works just fine
Things i've tried:
Firestore rules are read and write true, so it's not a rules error
Mocked Firestore with firebase-mock and Jest seems to work fine, however this is not a
solution, since i need to test data inside the database
Hope you can help me :)
You should change Jest's test environment from the default jsdom to node using jest --env=node or by setting the testEnvironment option to node in your Jest config.
Solved the problem myself, i was using the Firebase web client, I switched to the Admin SDK made specifically for servers, i guess it was some sort of auth problem, because the admin sdk automatically authenticates you in the db
This is a open issue on GitHub. I'm pasting my comment from that issue here to hopefully help some other people:
I experienced the same error message on 9.6.6 with NextJS. I believe
this error message could be presented due to a range of errors - as I
see 100+ Stackoverflow questions with this error message.
After lots of debugging I realized I accidently used SQL
capitalization:
.orderBy('time', 'ASC') = "INTERNAL ASSERTION FAILED: Unexpected state" .orderBy('time', 'asc') = No Errors!
This was a pain to debug, and my mistake was so small. Maybe better
error reporting is needed in cases like this? When you get then Google
this error message it easily leads you down a path of debugging things
completely irrelevant to the real error.
So pretty much - a tiny syntax error can cause the error message and lead you down a road of debugging the wrong things. To solve this you have to find exactly where it is happening and narrow in your debuging.
execute this command with what is indicated a little above yarn test jest --env=node
after this the error disappears

How would I create a new document, populate it, and then send it back as json?

I would like to update my API call that creates a new document, to create the new document, populate it, and then return the json response via express.
I have my model set up as follows:
import mongoose from 'mongoose';
import constants from '../../constants/enums';
const DepartmentBudgetSchema = new mongoose.Schema({
department : {
type : String,
enum : constants.departments
},
owner : {
type : mongoose.Schema.Types.ObjectId,
ref : 'Executive'
},
budget : Number
});
export default mongoose.model('DepartmentBudget', DepartmentBudgetSchema);
I have my API calls setup with my express paths, which make a call to my logic, which in turn makes a call to my controller, where I handle all the database work.
My express api call looks like the following:
import express from 'express';
import DepartmentsBudgetsLogic from './departmentBudget.logic.js';
import constants from '../../constants/enums';
const router = express.Router();
const code = constants.statusCode;
router.post('/', newDepartmentBudget);
async function newDepartmentBudget( req, res ) {
try {
const result = await new DepartmentsBudgetsLogic().newDepartmentBudget(req.body);
console.log(result);
res.status(code.created).json(result);
}
catch ( error ) {
console.error('Unable to create department budget.', error);
res.sendStatus(code.serverError);
}
}
Then my logic function simply calls my controller passing the budget object:
import DepartmentBudgetController from './departmentBudget.controller';
export default class DepartmentBudgetLogic {
newDepartmentBudget( budget ) {
return new DepartmentBudgetController().newDepartmentBudget(budget);
}
}
Finally, and this is where I think I am having my problem, the controller handles the mongoose work:
import DepartmentBudget from './departmentBudget.model';
export default class DepartmentBudgetController {
newDepartmentBudget( budget ) {
DepartmentBudget.create(budget).then(function( budget ) {
return budget.populate('owner').execPopulate();
});
}
}
The document gets created in the database correctly, but I am really struggling with the code to populate the owner field and then return the populated doc as my response.
I know from mongoose's docs that execPopulate() returns a promise that resolves to the populated document, but when I console.log the result in my express api call I get "undefined".
I'm still learning here, so I may have overlooked something very obvious.
Anyone have any ideas on what I'm doing wrong? Or is there a different direction I should go in so that I can accomplish the overall objective of being able to create a new document, populate it, and then return it in my response object.
Thank you!

Resources