Load a mongo collection without creating it if not exists - mongodb

with mongo db node driver v4.13, how can I load a mongo collection without creating it if not existing?
In earlier versions the function db.collection can be called like this:
db.collection('not_existing', { strict: true }, (err, res) => {
if (err) {
console.log('Collection does not exist');
}
});
But in v4.13 the callback version of this function does not exist anymore and strict: true seems to be ignored.
const collection = await db.collection('not_existing', { strict: true });
console.log(await db.listCollections().toArray()); // lists the collection

You can use
db.getCollectionNames().filter(x => x == 'not_existing').length > 0
or
db.runCommand({ listCollections: 1, filter: { name: 'not_existing' } }).cursor.firstBatch.length > 0
to check whether a collection exists or not.

Related

Sequelize (Postgres) always 'returning' null for second index (whether creating or updating)

Trying to correctly troubleshoot HTTP status codes and responses on upsert. I've scoured SO and google to find examples of this behavior, but the answers are always really old (pre Sequelize 6 era).
From what I gather over at Sequelize docs, UPSERT returns Promise<Model,boolean | null> and additionally For SQLite/Postgres, created value will always be 'null'. But apparently for me, whether it created/didn't update/updated, it always returns null
Am I correctly understanding that boolean return will return for update(T)/no update(F) and null for creation? Or will it only return null whether create|update|no update for postgres users?
This is MY expected return behavior:
data: [
{
id: 64920,
...etc...
},
null // null = created
],
data: [
{
id: 64921,
...etc...
},
false // false = no update (data is the same)
],
data: [
{
id: 64922,
...etc...
},
true // true = update complete (some data was new)
]
Sample controller upsert command:
exports.createOne = async (req, res, next) => {
Trip.upsert({
id: req.body.id,
...etc...
},{returning: true } // not needed, default in Sequelize =< 6.0
)
.then(function (test) {
if (test) {
res.status(200);
res.send("Successfully stored");
} else {
res.status(200);
res.send("Successfully inserted");
}
})
.catch((err) => {
res.status(500).json({ error: err.message });
});
};
Anyone have examples or suggestions to properly implement this?
Thank you!

mongoose.connect() is not creating a database?

I am using mongoose.connect() method but it couldn't created a DB ,i did even insert some documents in
db by using insertMany() but it neither giving me any error nor creating a DB as when i checked my mongo Shell todolistDB is not created .
const express = require('express')
const bodyParser = require('body-parser')
const mongoose = require('mongoose')
mongoose.connect('mongodb://localhost:27017/todolistDB', {
useNewUrlParser: true,
useUnifiedTopology: true },
function (err) {
if (err) {
console.log(err);
} else {console.log('server is connected');}})
const itemsSchema = mongoose.Schema({name: {type: String,required: true }})
const Item = mongoose.model('Item', itemsSchema)
const item1 = new Item({name: 'Welcome to your todo list!'})
const item2 = new Item({name: 'Hit + button to add new item'})
const item3 = new Item({name: '<-- click to delete a item!'})
const defaultItems = [item1, item2, item3]
app.get('/', function (req, res) {
Item.find({}, function (err, result) {
if (defaultItems.length===0) {
**even after insertmany method todolistDB is not created**
Item.insertMany(defaultItems, function (err) {
if (err) {
console.log(err);
} else {
console.log('new record inserted successfully!');}});
} else {
res.render('list', {listTitle: 'today',latestItems: result}) }
** when I used insertMany outside app.get() method then all records was inserted, I just started learning mongoDB sorry in advanced if it was a silly mistake **
detailed answer would be appreciated!
Consider the following three lines of your code:
[1] const defaultItems = [item1, item2, item3]
[2] Item.find({}, function (err, result) {
[3] if (defaultItems.length===0) {
In [2] you are doing a query, presumably it returns no results and you get to [3]. However in [3] you are referencing the fixed set defined in [1] which is of length 3. Thus the if statement in [3] is never entered.
The code is pretty fine.
mongoose.connect() call is fine. Since you are writing it in Promise form, issue is Unhandled Promise Rejection for connection failure.
Console the error, the error message would give us better glimpse.
Coming to the error possibilities, it is likely to happen if you use middleware handler app.use or router.use.
Please console the error, drop down the error message. So that I can help you further.
You Can Follow This Code
mongoose.connect('mongodb://localhost:27017/todolistDB', {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
useFindAndModify: false
})
mongoose.connection.on("connected", () => {
console.log("Mongodb connected")
})
mongoose.connection.on("error", errMsg => {
console.log("Error connecting database. Msg: " + errMsg)
})

Asynchronous Issues with JEST and MongoDB

I am getting inconsistent results with JEST when I try to remove items from a MongoDB Collection using the beforeEach() Hook.
My Mongoose schema and model defined as:
// Define Mongoose wafer sort schema
const waferSchema = new mongoose.Schema({
productType: {
type: String,
required: true,
enum: ['A', 'B'],
},
updated: {
type: Date,
default: Date.now,
index: true,
},
waferId: {
type: String,
required: true,
trim: true,
minlength: 7,
},
sublotId: {
type: String,
required: true,
trim: true,
minlength: 7,
},
}
// Define unique key for the schema
const Wafer = mongoose.model('Wafer', waferSchema);
module.exports.Wafer = Wafer;
My JEST tests:
describe('API: /WT', () => {
// Happy Path for Posting Object
let wtEntry = {};
beforeEach(async () => {
wtEntry = {
productType: 'A',
waferId: 'A01A001.3',
sublotId: 'A01A001.1',
};
await Wafer.deleteMany({});
// I also tried to pass in done and then call done() after the delete
});
describe('GET /:id', () => {
it('Return Wafer Sort Entry with specified ID', async () => {
// Create a new wafer Entry and Save it to the DB
const wafer = new Wafer(wtEntry);
await wafer.save();
const res = await request(apiServer).get(`/WT/${wafer.id}`);
expect(res.status).toBe(200);
expect(res.body).toHaveProperty('productType', 'A');
expect(res.body).toHaveProperty('waferId', 'A01A001.3');
expect(res.body).toHaveProperty('sublotId', 'A01A001.1');
});
}
So the error I always get is related to duplicate keys when I run my tests more than once:
MongoError: E11000 duplicate key error collection: promis_tests.promiswts index: waferId_1_sublotId_1 dup key: { : "A01A001.3", : "A01A001.1" }
But I do not understand how I can get this duplicate key error if the beforeEach() were firing properly. Am I trying to clear the collection improperly? I've tried passing in a done element to the before each callback and invoking it after delete command. I've also tried implementing the delete in beforeAll(), afterEach(), and afterAll() but still get inconsistent results. I'm pretty stumped on this one. I might just removed the schema key all together but I would like to understand what is going on here with the beforeEach(). Thanks in advance for any advice.
It might be because you are not actually using the promise API that mongoose has to offer. By default, mongooses functions like deleteMany() do not return a promise. You will have to call .exec() at the end of the function chain to return a promise e.g. await collection.deleteMany({}).exec(). So you are running into a race condition. deleteMany() also accepts a callback, so you could always wrap it in a promise. I would do something like this:
describe('API: /WT', () => {
// Happy Path for Posting Object
const wtEntry = {
productType: 'A',
waferId: 'A01A001.3',
sublotId: 'A01A001.1',
};
beforeEach(async () => {
await Wafer.deleteMany({}).exec();
});
describe('GET /:id', () => {
it('Return Wafer Sort Entry with specified ID', async () => {
expect.assertions(4);
// Create a new wafer Entry and Save it to the DB
const wafer = await Wafer.create(wtEntry);
const res = await request(apiServer).get(`/WT/${wafer.id}`);
expect(res.status).toBe(200);
expect(res.body).toHaveProperty('productType', 'A');
expect(res.body).toHaveProperty('waferId', 'A01A001.3');
expect(res.body).toHaveProperty('sublotId', 'A01A001.1');
});
}
Also, always expect the assertions with asynchronous code
https://jestjs.io/docs/en/asynchronous.html
You can read more about mongoose promises and query objects here
https://mongoosejs.com/docs/promises.html
Without deleting the schema index this seems to be the most reliable solution. Not 100% sure why it works over async await Wafer.deleteMany({});
beforeEach((done) => {
wtEntry = {
productType: 'A',
waferId: 'A01A001.3',
sublotId: 'A01A001.1',
};
mongoose.connection.collections.promiswts.drop(() => {
// Run the next test!
done();
});
});

JSON formatting when saving using Mongoose is not bringing back the expected result

I have a code block in my Mongoose controller which attempts to find both Projects and Levels:
exports.landing = (req, res, next) => {
console.log(req.params.projectid);
Project.findById(req.params.projectid, (err, project) => {
if (err) return res.status(500).send(err);
//find the level based on the projectid
Level.find({'projectid': req.params.projectid}, (err, level) => {
if (err) return res.status(500).send(err);
//find the level based on the projectid
res.json({
success: true,
message: 'got',
level: level.leveltempnodes
});
//res.render(path + 'project', {project: project, moment: moment, level: level});
});
});
};
Within the res.json section, If I just use 'level' without the dot notation, all the results come back as expected. When I try and get the 'levelnodes' entry, nothing comes back. The only thing I see differently with the level document compared to the other documents is that the JSON result includes a '[':
{"success":true,"message":"got","level":{"_id":"5b4205ea5b44e146b5978175" ...
The above works fine. But I am not able to use dot syntax on the below result:
{"success":true,"message":"got","level":[{"_id":"5b4202fc94855d56204c8bb7"
I am saving the level document like this:
var data = {
levelname: levelname,
leveltempnodes: leveltempnodes,
projectid: projectid};
var level = new Level(data);
level.save(function (err) {
if (err) return handleError(err);
})
My error is nothing is coming back at all:
{"success":true,"message":"got"}
Schema:
const mongoose = require('mongoose');
const LevelSchema = mongoose.Schema({
levelname: String,
leveltempnodes: String,
projectid: String
});
module.exports = mongoose.model('Level', LevelSchema);
Data is being stored on the DB without issue. I am adding it via Ajax:
var p = {
projectname : $("#projectname").val(),
levelname : 'Root',
leveltempnodes : '{"class":"go.GraphLinksModel","nodeKeyProperty":"id","nodeDataArray":[{"id":1,"loc":"226 226","text":"sensor"},{"text":"perception","loc":"426 225.99999999999997","id":-2},{"text":"planning","loc":"626 225.99999999999997","id":-3},{"text":"gate","loc":"826 225.99999999999997","id":-4}],"linkDataArray":[{"from":1,"to":-2,"text":"msg","points":[296.7874157629703,237.73538061447854,340.03133208792605,227.76937481449303,383.33478829426565,227.0952320784595,426.7981545990892,236.1401244399739]},{"from":-2,"to":-3,"text":"msg","points":[523.225709890083,236.1861908341044,558.0349502392196,229.00680324793404,592.1479459982006,228.54232080927673,626.6289592123036,236.76409981273324]},{"from":-3,"to":-4,"text":"msg","points":[709.6483081744094,237.23795381070627,748.7663709980919,229.48139598538538,787.383185499046,229.48139598538538,826.1210439041331,238.64104211943584]}]}',
}
if(p.projectname == ''){
console.log('e');
}else{
$.ajax({
type: 'POST',
contentType : "application/json",
url: 'api/project/save',
data : JSON.stringify(p),
success: function(res) {
window.location.replace("/project/"+res.id);
}
});

Mongoose select,populate and save behaving differently on Mac and Windows

Here's what i did
static populateReferralLinks(){
return Promise.coroutine(function*(){
let companies = yield Company.find({},'billing referral current_referral_program')
.populate('billing.user','emails name');
for(let i = 0 ; i < length ; i++){
companies[i].referral.is_created = true;
companies[i].referral.referral_email = companies[i].billing.user.emails[0].email;
companies[i] = yield companies[i].save();
}
return companies;
}).apply(this)
.catch((err) => {
throw err;
});
}
I have a funciton in which i am selecting only 3 fields to go ahead with i.e billing,current_referral_program and referral.
And populating user using the reference stored in billing.user.
Now when i call this function then on line
companies[i].save();
The following command is shown in the terminal in windows
Mongoose: companies.update(
{ _id: ObjectId("58d12e1a588a96311075c45c") },
{ '$set':
{ billing:
{ configured: false,
user: ObjectId("58d12e16588a96311075c45a") },
referral:
{ is_created: true,
referral_email: 'jadon.devesh98#gmail.com',
},
updatedAt: new Date("Wed, 22 Mar 2017 12:02:55 GMT")
}
}
)
But in Mac's terminal it shows this command
Mongoose: companies.update({ _id: ObjectId("58d12e1a588a96311075c45c") }) { '$set': { billing: { configured: false, user: ObjectId("58d12e16588a96311075c45a") }, current_limit: {}, current_usage: {},referral: { is_created: true, referral_email: 'jadon.devesh98#gmail.com'}}, '$unset': { updatedAt: 1 } }
Now, I haven't mentioned current_limit and current_usage to be empty. it's executing fine on windows but on Mac it's setting current_limit and current_usage empty thus updating my document with empty objects on Mac but not on windows.
It should behave same way on both OS but it is not.
Apparently this problem was there in Mongoose 4.5.8 and is resolved in the latest version i.e 4.9.1
Check it here