mongoose delete duplicate docs but not the first one - javascript

I used findOneAndRemove to delete duplicate because I knew there was not more than 2 docs with the same "name" value. That would delete the first instance of a doc that has the same "name" value. Now I don't want to delete the first instance. Instead, I want to delete all the other ones. so if there are 3 docs that have the {name: "/face.com"} it should only leave the first one that was added and delete the other 2.
Comps.find({}).lean()
.then(function(comps){
findDuplicates.getArrayOfNames(comps);
var dups = findDuplicates.checkForDuplicates();
//dups is an array of names. It contains a list like ["/face.com", "/example.com"]. those are the ones that are duplicates.
console.log("DUPS::", dups)
dups.forEach(function(e){
var query = {name : e}
Comps.findOneAndRemove(query, function(err, removed){
if(err) console.log(err);
console.log("removed: ", removed)
})
})
console.log("length: ", comps.length);
})
.catch(function(err){
console.log("ERR",err)
})

Related

How to perform mongoose deleteMany() with query operators?

I want to delete X number of posts starting from the most recently created for a specific user.
How can I apply this logic using mongoose so that I can perform just ONE database operation instead of first having to query for these posts and remove them one by one?
I am finding using the query and projection operators with the $ very confusing, any help would be appreciated.
Below I added pseudo code on how it should to work.
Thank you!
const userId = "123456"
const deleteCount = 6
const deletedPosts = await Post.deleteMany({
.where { userid == userId) }
.sort({createdAt: -1}) // delete by most recent
.limit(deleteCount) // only delete 6 (most recent) posts
}, {new: true}) // return results of operation
console.log(deletedPosts.deletedCount) // -> should be "6"
You can't set a limit when using deleteMany or findAndModify. So, if you want to precisely limit the number of documents removed, you'll need to do it in two steps.
db.getCollection('users').find({}, {class : 4}) .limit(2) .sort({StudentAge: -1}) .toArray() .map(function(doc) { return doc._id; }); //returns the array of id's
db.getCollection('users').deleteMany({_id: {$in: [ "s3", "s4" ]}})//put the array of id's

node js sql output

I am trying to come up with the node.js code to get the output of this query:
const viewAllEmployees = () => {
let sql = 'SELECT e.id, e.first_name, e.Last_name, r.title, d.name as "Department", salary, CONCAT (m.first_name," ", m.last_name) AS "Manager"
FROM employee e ' + connection.escape('INNER JOIN employee m
ON e.manager_id = m.id
LEFT JOIN role r
ON e.role_id = r.id
LEFT JOIN department d
on r.department_id = d.id');
connection.query(sql, (err, res) => {
if (err) throw err;
console.table(res);
// console.log(res);
//connection.end();
});
The problem is that when I use it without the connection.escape(), I get the output, but with single quotes like this:
How can I (1) get rid of the (index) column, and (2) get rid of the single quotes?
Getting rid of the single quotes is really the priority.
Thanks!
Index column and quotes are added by console.table function itself.
You can check it running console.table with any static data like here:
https://developer.mozilla.org/en-US/docs/Web/API/Console/table#collections_of_primitive_types
To print it in a way you want it, implement printing function on your own.

Javascript ForEach on Array of Arrays

I am looping through a collection of blog posts to firstly push the username and ID of the blog author to a new array of arrays, and then secondly, count the number of blogs from each author. The code below achieves this; however, in the new array, the username and author ID are no longer separate items in the array, but seem to be concatenated into a single string. I need to retain them as separate items as I need to use both separately; how can I amend the result to achieve this?
var countAuthors = [];
blogAuthors = await Blog.find().populate('authors');
blogAuthors.forEach(function(blogAuthor){
countAuthors.push([blogAuthor.author.username, blogAuthor.author.id]);
})
console.log(countAuthors);
// Outputs as separate array items, as expected:
// [ 'author1', 5d7eed028c298b424b3fb5f1 ],
// [ 'author2', 5dd8aa254d74b30017dbfdd3 ],
var result = {};
countAuthors.forEach(function(x) {
result[x] = (result[x] || 0) + 1;
});
console.log(result);
// Username and author ID become a single string and cannot be accessed as separate array items
// 'author1,5d7eed028c298b424b3fb5f1': 15,
// 'author2,5dd8aa254d74b30017dbfdd3': 2,
Update:
Maybe I can explain a bit further WHY on what to do this. What I am aiming for is a table which displays the blog author's name alongside the number of blogs they have written. However, I also want the author name to link to their profile page, which requires the blogAuthor.author.id to do so. Hence, I need to still be able to access the author username and ID separately after executing the count. Thanks
You could use String.split().
For example:
let result = 'author1,5d7eed028c298b424b3fb5f1'.split(',')
would set result to:
['author1' , '5d7eed028c298b424b3fb5f1']
You can then access them individually like:
result[1] //'5d7eed028c298b424b3fb5f1'
Your issue is that you weren't splitting the x up in the foreach callback, and so the whole array was being converted to a string and being used as the key when inserting into the results object.
You can use array destructuring to split the author name and blog id, and use them to optionally adding a new entry to the result object, and then update that result.
countAuthors = [
['author1', 'bookId1'],
['author2', 'bookId2'],
['author1', 'bookId3'],
['author1', 'bookId4'],
['author2', 'bookId5']
]
var result = {};
countAuthors.forEach(([author, id]) => {
if (result[author] === undefined) {
result[author] = {count: 0, blogIds: []};
}
result[author].count += 1;
result[author].blogIds.push(id);
});
console.log(result);

How to find "By Name" in mongoose

I am trying to get database values using a specific name. I want to get all the books an author written.
This is my code to get the first name of the author and search for all the books he's written in BookDB using Like operator as in mysql
//get books by author name
router.route('/authorName').get((req, res) => {
let authorName = req.params.authorName; //how can i pass this value to below regex command
BookDB.find({"firstName": /authorName/}, (err, books) => {
if(err) throw err;
res.status(200).send(books);
});
});
Problem: How can I pass authorName to the {"firstName": /authorName/}.
The way I have written, it is not set the authorName properly.
I am not sure in the mongoose part, but you can also create regular expressions as:
new RegExp(exp: string, flags: string)
Note if you use this format, the start and end slash has no special meaning, they would mean the string starts with a slash
I did some research and found $regex.
//get books by author name
router.route('/authorName').get((req, res) => {
let authorName = req.params.authorName;
BookDB.find({firstName: {$regex: `${authorName}`}}, (err, books) => {
if(err) throw err;
res.status(200).send(books);
});
});
This will find all the results that containing this particular string authorName in BookDB database

node-mssql Transaction insert - Returning the inserted id..?

I'm using node-mssql 3.2.0 and I need to INSERT INTO a table and return the id of the inserted record.
I can successfully use sql.Transaction() to insert data, but the only parameters given to callbacks (request.query() and transaction.commit()) are:
const request = new sql.Request();
request.query('...', (err, recordset, affected) => {});
const transaction = new sql.Transaction();
transaction.commit((err) => {});
So recordset is undefined for INSERT, UPDATE and DELETE statements, and affected is the number of rows affected, in my case 1.
Does anyone know a good way to obtain an inserted records id (just a primary key id) after a transaction.commit() using node-mssql..?
Instead of just doing an INSERT INTO... statement, you can add a SELECT... statement as well:
INSERT INTO table (...) VALUES (...); SELECT SCOPE_IDENTITY() AS id;
The SCOPE_IDENTITY() function returns the inserted identity column, which means recordset now contains the id:
const request = new sql.Request();
request.query('...', (err, recordset, affected) => {});
I don't think request.multiple = true; is required, because although this includes multiple statements, only one of them is a SELECT... and so returns.
So the answer was SQL related and is not specific to node-mssql.
I know this question has accepted answer.
I made the following way:
let pool = await sql.connect(config);
let insertItem = await pool.request()
.input('ItemId',sql.NVarChar, 'itemId1234')
.input('ItemDesc',sql.NVarChar, 'nice item')
.query("insert into itemTable (Id, ItemId,ItemDesc) OUTPUT INSERTED.ID
values (NEWID(), #ItemId, #ItemDesc);
var insertedItemId = insertItem.recordset[0].ID
This adds unique identifier to data that is saved to db (if table is created so)
create table itemTable(
Id UNIQUEIDENTIFIER primary key default NEWID(),
ItemId nvarchar(25),
ItemDesc nvarchar(25)
)

Categories

Resources