MongoDB E11000 duplicate key error collection (duplicate key error) - javascript

I am trying to write an array to my mongodb and i keep getting this error...
UnhandledPromiseRejectionWarning: MongoError: E11000 duplicate key
error collection: test.strains index: id dup key: { _id:
ObjectId('5ec18ebc5c7b4f6149499d93') }
adding to db
const upsertStrain = async (strainObj) => {
const DB_URL =
"mongodb_url";
if (mongoose.connection.readyState == 0) {
mongoose.connect(DB_URL);
}
// if this strain exists, update the entry, don't insert
let conditions = { name: strainObj.name };
let options = { upsert: true, new: true, setDefaultsOnInsert: true };
await Strain.findOneAndUpdate(
conditions,
strainObj,
options,
(err, result) => {
if (err) throw err;
}
);
};
calling function
for(strain of strains) {
await upsertStrain({
name: strain.name,
mood: strain.mood,
dateCrawled: new Date(),
});
}
Schema:
let strainSchema = new mongoose.Schema(
{
name: {
type: String,
sparse: true,
unique: true
},
mood: {
type: String,
sparse: true,
unique: false
},
dateCrawled: {
type: Date,
sparse: true
},
}
);
The the array that i am trying to add looks like this...
[
{
"name": "Blackberry Hashplant",
"mood": "Sleepy"
},
{
"name": "Walrus Kush",
"mood": "Happy"
},
{
"name": "Cherry Cheesecake",
"mood": "Sleepy"
},
{
"name": "Gorilla Cake",
"mood": "Hungry"
},
{
"name": "Divorce Cake",
"mood": ""
},
{
"name": "Biscotti",
"mood": ""
},
{
"name": "Kush Mints",
"mood": ""
},
{
"name": "Cookie Dawg",
"mood": ""
},
{
"name": "Cake Batter",
"mood": ""
},
{
"name": "Crazy Glue",
"mood": ""
},
{
"name": "Grapefruit Sour Dream",
"mood": ""
},
{
"name": "Gelato Cake",
"mood": ""
},
{
"name": "Garanimals",
"mood": ""
}
]
please help...been stuck on this for a while

Related

How to access nested elements of json object in node js and mongodb

const mongoose = require("mongoose");
const productSchema = mongoose.Schema({
product_name: {
type: String,
required: [true, "Must Enter Product Name"],
},
product_brand: {
type: String,
},
category: {
type: String,
required: [true, "Must Enter Product Catagorey"],
},
reviews: [
{
name: {
type: String,
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
comment: {
type: String,
required: true,
},
rating: {
type: Number,
// required: true,
},
},
{ timestamps: true },
],
owner: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
});
module.exports = mongoose.model("Product", productSchema);
Here I want to access the values of commet for Appling filters
Here is is the output of my products
[
{
"_id": "63c4ee520ca7722674d007d5",
"product_name": "Headphones",
"product_description": "xvy",
"product_price": 8000,
"product_brand": "Apple",
"product_color": "White",
"product_stoke": 3,
"category": "Headphones",
"product_image": "public\\images\\uploaded\\products\\167385045002297820433-5f2f-43d1-972a-4b33785393ee.0ad829318c5599f429d2a6e625f8bde3.jpeg",
"product_sku": "#1",
"owner": "63c4ed720ca7722674d007ab",
"reviews": [
{
"name": "Daniyal Alam",
"user": "63c43d54cf582066929c8c46",
"comment": "Good Mobbile Phone",
"rating": 4,
"_id": "63cbce2cd52bf9ecfdf29323"
}
],
"__v": 1
},
{
"_id": "63c4e3530ca7722674d006b6",
"product_name": "Air bud Two.",
"product_description": "In the busy world which is fil.",
"product_price": 50000,
"product_brand": "Apple",
"product_color": "White",
"product_stoke": 5,
"category": "Headphones",
"product_image": "public\\images\\uploaded\\products\\167384763581197820433-5f2f-43d1-972a-4b33785393ee.0ad829318c5599f429d2a6e625f8bde3.jpeg",
"product_sku": "33",
"owner": "63c4d8ac0ca7722674d00529",
"reviews": [],
"__v": 0
},
]
I want to access my comments I tried the following code but it only returns reviews
exports.commentProduct = async (req, res, next) => {
const newproduct = await Product.find({});
try {
const reviews = newproduct?.map((p) => {
if (typeof p.reviews != "undefined") {
console.log(p.reviews);
}
});
const com = reviews?.map((c) => {
// console.log(comments);
});
// const comments = reviews.comment;
return res.status(200).json({
success: true,
reviews,
});
} catch (error) {
return res.status(500).json({
success: false,
message: error.message,
});
}
};
the Console Prints products having reviews but after applying dot notation on reviews I got undefined
[
{
name: 'Daniyal Alam',
user: new ObjectId("63c43d54cf582066929c8c46"),
comment: 'BEst One',
rating: 5,
_id: new ObjectId("63cbce44d52bf9ecfdf29743")
}
]
[]
[]
[]
[]
[]
[]
[]
[]
[
{
name: 'Daniyal Alam',
user: new ObjectId("63c43d54cf582066929c8c46"),
comment: 'pp',
rating: 4,
_id: new ObjectId("63c4f76e0ca7722674d040ae")
}
]
[]
[
{
name: 'Daniyal Alam',
user: new ObjectId("63c43d54cf582066929c8c46"),
comment: 'Good Mobbile Phone',
rating: 4,
_id: new ObjectId("63cbce2cd52bf9ecfdf29323")
}
]
Working with your example, you can map each item, then map the reviews, and get the comment out of each like using the following code
const data = [{
"_id": "63c4ee520ca7722674d007d5",
"product_name": "Headphones",
"product_description": "xvy",
"product_price": 8000,
"product_brand": "Apple",
"product_color": "White",
"product_stoke": 3,
"category": "Headphones",
"product_image": "public\\images\\uploaded\\products\\167385045002297820433-5f2f-43d1-972a-4b33785393ee.0ad829318c5599f429d2a6e625f8bde3.jpeg",
"product_sku": "#1",
"owner": "63c4ed720ca7722674d007ab",
"reviews": [{
"name": "Daniyal Alam",
"user": "63c43d54cf582066929c8c46",
"comment": "Good Mobbile Phone",
"rating": 4,
"_id": "63cbce2cd52bf9ecfdf29323"
}],
"__v": 1
}]
data.map((dat) => {
dat["reviews"].map((rev) => {
document.querySelector('div').innerHTML +=rev["comment"]
})
})
<div></div>

How to calculate sum of fields using mongoose and nodejs api based on a search result

I'm trying to retrieve the sum of some fields based on a search result and filter and I want to do the summation and apply it only to the search result
In my application based on nodejs and mongoose, I have a search process for the user's payment transaction records, which are divided into two parts, or filtered into two parts, which are the balance consumption records and the balance top-up records as follows
I do a filtering process through Query while searching and retrieving records. This is the result of the search
What I really want is to create a new dummy field that does not exist in the database, and it is included in the data returned from the request sent in the previous image, and it calculates the total points based on the search result
I found this code online and tried it
I tried to configure it to fit the data I had
This code returns the result separately from the search process that I intend to retrieve, and this is normal since it contains a different result
It also returns the result of collecting points for all users, and this is something I do not need
History.aggregate(
[{ $group: { _id: "$userId", total: { $sum: "$point"}}}],
function(err, result) {
if (err) {
res.send(err);
} else {
res.json(result);}});
this findAllHistory
const findAllHistory = async (req,res) => {
try {
let loginUser = { _id: req.user.id };
let foundUserLogin = await dbService.findOne(user, loginUser);
let options = {};
let query = {};
let validateRequest = validation.validateFilterWithJoi(
req.body,
HistorySchemaKey.findFilterKeys,
History.schema.obj
);
if (!validateRequest.isValid) {
return res.validationError({ message: `${validateRequest.message}` });
}
if (typeof req.body.query === 'object' && req.body.query !== null) {
query = { ...req.body.query };
}
query.categoryHistory = {$ne: 1};
query.payeeId = req.user.id;
if (req.body.isCountOnly){
let totalRecords = await dbService.count(History, query);
return res.success({ data: { totalRecords } });
}
if (req.body && typeof req.body.options === 'object' && req.body.options !== null) {
options = { ...req.body.options };
}
// let foundHistorys = await dbService.paginate(History,{ $or: [ { payeeId: req.user.id }, { categoryHistory: { $lt: 4 } } ] } );
let foundHistorys = await dbService.paginate( History,query,options);
if (!foundHistorys || !foundHistorys.data || !foundHistorys.data.length){
return res.recordNotFound();
}
/* History.aggregate(
[{ $group: { _id: "$userId", total: { $sum: "$point"}}}],
function(err, result) {
if (err) {
res.send(err);
} else {
res.json(result);}});
*/
return res.success({ data :foundHistorys });
} catch (error){
return res.internalServerError({ message:error.message });
}
};
this Schema
const myCustomLabels = {
totalDocs: "itemCount",
docs: "data",
limit: "perPage",
page: "currentPage",
nextPage: "next",
prevPage: "prev",
totalPages: "pageCount",
pagingCounter: "slNo",
meta: "paginator",
};
mongoosePaginate.paginate.options = { customLabels: myCustomLabels };
const Schema = mongoose.Schema;
const schema = new Schema({
userId: {
type: Schema.Types.ObjectId,
ref: "user",
required: true,
unique: false,
},
isDeleted: { type: Boolean },
date: { type: Date },
point: {
type: Number,
min: 1,
unique: false,
required: true,
},
description: {
lowercase: false,
trim: true,
unique: false,
type: String,
required: true,
minLength: 6,
maxLength: 100,
uniqueCaseInsensitive: true,
},
categoryHistory: {
type: Number,
enum: CategoryHistoryEnum.Category_History,
required: true,
unique: false,
},
payeeId: {
type: Schema.Types.ObjectId,
ref: "user",
required: true,
unique: false,
},
pointDirection: {
default: false,
type: Boolean,
required: true,
},
});
this res
{
"status": "SUCCESS",
"message": "Your request is successfully executed",
"data": {
"data": [
{
"userId": "6372886e89d36d38b75a774b",
"date": "2022-11-18 11:1 pm",
"point": 50,
"description": "test",
"categoryHistory": 3,
"payeeId": "6372886e89d36d38b75a774b",
"pointDirection": true,
"isDeleted": false,
"id": "6377e495541a7889acf1cfc6"
},
{
"userId": "6372886e89d36d38b75a774b",
"date": "2022-11-18 11:2 pm",
"point": 50,
"description": "test",
"categoryHistory": 3,
"payeeId": "6372886e89d36d38b75a774b",
"pointDirection": true,
"isDeleted": false,
"id": "6377e4c4541a7889acf1cfdb"
},
{
"userId": "6372886e89d36d38b75a7741",
"date": "2022-11-19 12:27 am",
"point": 5,
"description": "test",
"categoryHistory": 2,
"payeeId": "6372886e89d36d38b75a774b",
"pointDirection": false,
"isDeleted": false,
"id": "6377f8bbe8ca063c5a5deef4"
}
],
"paginator": {
"itemCount": 3,
"offset": 0,
"perPage": 10,
"pageCount": 1,
"currentPage": 1,
"slNo": 1,
"hasPrevPage": false,
"hasNextPage": false,
"prev": null,
"next": null
}
}
}
Please help me to make the result as follows
{
"status": "SUCCESS",
"message": "Your request is successfully executed",
"data": {
"data": [
{
"userId": "6372886e89d36d38b75a774b",
"date": "2022-11-18 11:1 pm",
"point": 50,
"description": "test",
"categoryHistory": 3,
"payeeId": "6372886e89d36d38b75a774b",
"pointDirection": true,
"isDeleted": false,
"id": "6377e495541a7889acf1cfc6"
},
{
"userId": "6372886e89d36d38b75a774b",
"date": "2022-11-18 11:2 pm",
"point": 50,
"description": "test",
"categoryHistory": 3,
"payeeId": "6372886e89d36d38b75a774b",
"pointDirection": true,
"isDeleted": false,
"id": "6377e4c4541a7889acf1cfdb"
},
],
"total point": 100, // Add This to res //
"paginator": {
"itemCount": 3,
"offset": 0,
"perPage": 10,
"pageCount": 1,
"currentPage": 1,
"slNo": 1,
"hasPrevPage": false,
"hasNextPage": false,
"prev": null,
"next": null
}
}
}

Mongoose update subdocument by key

for the following collection:
id: Number
name:[
new Schema({
language: { type: String, enum: ['en-US', 'fr-CA'] },
text: String,
},{ _id: false }
);
],
isActive: Boolean
and sample data like the following:
{
id:1,
"name": [
{"language": "en-US", "text": "Book"},
{"language": "fr-CA", "text": "livre"}
],
isActive:true
// and so many other fields
},
{
id:2,
"name": [
{"language": "en-US", "text": "Pen"}
],
isActive:true
// and so many other fields
}
I would like to update the document by Id:1 and change the text only for french, I tried by:
const input={ "id":"1", "isActive": false}
const name= { "name": [{"language": "fr-CA", "text": "Nouvel article"}]}
await langs.findByIdAndUpdate(
{ _id: input.id },
{ ...input, $addToSet: { name } },
{ new: true, upsert: true }
);
but the result is: (added another french item)
{
id:1,
"name": [
{"language": "en-US", "text": "Book"},
{"language": "fr-CA", "text": "livre"},
{"language": "fr-CA", "text": "Nouvel article"}
],
isActive:false
},
This is based on Brit comment:
https://mongoplayground.net/p/atlw5ZKoYiI
Please advise.
As long as that attribute already exists on the document, you can do something like:
Collection.findOneAndUpdate({id: 1}, {
$set: {
"name.$[elem]": name
}
},
{
arrayFilters: [ { "elem.language": name.language } ],
upsert: true,
new: true
})

How to group an array of objects in javascript?

I'm trying to group an array of objects. The array should be grouped following this quote:
Group by type respecting the sequence.
Array I wish to group
var arrayObj = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
The way I want it to be grouped:
var newArray = [
[
{type: "user", text: "user1"},
{type: "user", text: "user2"},
{type: "user", text: "user3"}
],
[
{type: "clerk", text: "clerk1"}
],
[
{type: "user", text: "user4"}
],
[
{type: "clerk", text: "clerk2"},
{type: "clerk", text: "clerk3"}
],
[
{type: "user", text: "user5"},
{type: "user", text: "user6"}
]
];
What i tried:
I'm trying to use a filter, but without success since it even groups, but it groups all that are of the same type without respecting the sequence I want (from the array above);
var arrayObj = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
var newArray = [];
newArray.push(filtrarArray(arrayObj, 'clerk'));
newArray.push(filtrarArray(arrayObj, 'user'));
console.log(newArray);
function filtrarArray(array, type) {
return array.filter(function (val) {
return val.type === type;
});
}
The snippet below first sorts the array by type, which then makes it easy to loop through and group. Let me know if this solves your problem :)
EDIT
Just realized you didn't need sorting, so I commented the sort function out, but it's always there to be uncommented if you change your mind :)
const arrayObj = [
{ type: 'user', text: 'user1' },
{ type: 'user', text: 'user2' },
{ type: 'user', text: 'user3' },
{ type: 'clerk', text: 'clerk1' },
{ type: 'user', text: 'user4' },
{ type: 'clerk', text: 'clerk2' },
{ type: 'clerk', text: 'clerk3' },
{ type: 'user', text: 'user5' },
{ type: 'user', text: 'user6' },
];
const group = ar =>
ar
// .sort((a, b) => (a.type < b.type ? -1 : 1))
.reduce((newAr, obj, i) => {
if (0 === i) return [[obj]];
if (obj.type === newAr[newAr.length - 1][0].type)
return newAr[newAr.length - 1].push(obj), newAr;
return [...newAr, [obj]];
}, []);
const groupedAr = group(arrayObj);
console.log(groupedAr);
function groupConsecutive(arrayObj) {
if (arrayObj.length === 0) {
return [];
}
let matchedTypesIndex = 0;
let newArray = [
[
arrayObj[0]
]
];
let currentType = arrayObj[0]["type"];
let i = 1;
while (i < arrayObj.length) {
if (arrayObj[i]["type"] === currentType) {
newArray[matchedTypesIndex].push(arrayObj[i]);
} else {
currentType = arrayObj[i]["type"];
newArray.push([]);
matchedTypesIndex++;
newArray[matchedTypesIndex].push(arrayObj[i]);
}
i++;
}
return newArray;
}
This is probably not best pure solution but works as you need.
var arrayObj = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
let lastType;
let arr = [];
let arrIndex = -1;
arrayObj.forEach(obj => {
if(obj.type == lastType) { // add item into last group array by index
arr[arrIndex].push(obj);
}
else { // or add new group array
lastType = obj.type;
arrIndex++;
arr.push([obj]);
}
})
console.log(arr);
See This solution it will work
var arrayObj = [
{ type: "user", text: "user1" },
{ type: "user", text: "user2" },
{ type: "user", text: "user3" },
{ type: "clerk", text: "clerk1" },
{ type: "user", text: "user4" },
{ type: "clerk", text: "clerk2" },
{ type: "clerk", text: "clerk3" },
{ type: "user", text: "user5" },
{ type: "user", text: "user6" },
];
let typeNow = arrayObj[0].type;
let res = [];
let resultArray = [];
arrayObj.forEach((obj, i) => {
if (obj.type == typeNow) {
resultArray.push(obj);
} else {
resultArray = [obj];
res.push(resultArray);
typeNow = obj.type;
}
if (i == arrayObj.length - 1) res.push(resultArray);
});
console.log(res);
This is best solution can i have
It seem unordred because of Browser auto order but if you try in js file it will work and ordred
I'm responding with another way I found to solve my problem. This is just one more way I decided to comment.
Let's go:
I'm traversing the arrayObjects array using the appropriate loop for arrays for...of and then checking if the variable I set for arrayObjects (loopArrObj) has a different value of type of the variable (typeValue), if it is inserted at the end of the new array (grouping) using the array method push an empty array and then assign the value of the loopArrObj(Ie, there will be in the array grouping array empty only for the values ​​that are different).
So far so good, we have the first empty array. Next I'm defining this empty array with the push method the loopArrObj object in question, then we get the value through the console. I'm removing 1 from grouping.lengh so the loop assigns from 0 and not 1.
var arrayObjects = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
let typeValue,
grouping = [],
loopArrObj;
for (loopArrObj of arrayObjects) {
if (loopArrObj.type !== typeValue) {
grouping.push([]);
typeValue = loopArrObj.type;
}
grouping[grouping.length - 1].push(loopArrObj);
}
console.log(grouping);

Getting foreign key undefine in Console.log and in api response

I have table report_data which is belongs to daily_entry table but when I call api like to get all data of daily_entry table it send response like below
output
{
"response_code": "0",
"message": "Operation is successfully executed",
"status": "success",
"data": {
"id": 1,
"user_id": 1,
"date": "12-10-2020",
other data ....
"is_active": true,
"createdAt": "2020-10-21T06:25:57.877Z",
"updatedAt": "2020-10-21T06:25:57.877Z",
"report_datum": {
"id": 1,
"entry_i": 1, <<<<<<<----------OUTPUT
"Date": null,
"report_document_id": "2",
"createdAt": "2020-10-21T06:26:02.642Z",
"updatedAt": "2020-10-21T06:26:02.642Z"
}
},
"level": "info",
"timestamp": "2020-10-21T06:25:45.947Z"
}
expected
{
"response_code": "0",
"message": "Operation is successfully executed",
"status": "success",
"data": {
"id": 1,
"user_id": 1,
"date": "12-10-2020",
other data ....
"is_active": true,
"createdAt": "2020-10-21T06:25:57.877Z",
"updatedAt": "2020-10-21T06:25:57.877Z",
"report_data": {
"id": 1,
"entry_id": 1,<<<<<-------------EXPECTED
"Date": null,
"report_document_id": "2",
"createdAt": "2020-10-21T06:26:02.642Z",
"updatedAt": "2020-10-21T06:26:02.642Z"
}
},
"level": "info",
"timestamp": "2020-10-21T06:25:45.947Z"
}
relation between both table is hasOne
db.daily_entry.hasOne(db.report_data, { onDelete: "cascade", foreignKey: 'entry_id', foreignKeyConstraint: true, targetKey: 'id' });
I have logged data coming from db it was like below
dataValues:{id: 1, entry_i: 1, daily_entry : 8468476, date: 23-10-2020, …}
get entry_id:ƒ () {\n return this.get(attribute);\n }
undefined
I have checked in my whole project there is no name like entry_i
API I code is below
getdaily_entryById: async (req, res) => {
sequelize.sequelize.transaction(async (t1) => {
if (!req.params.id) {
logger.warn(error.MANDATORY_FIELDS)
return res.status(500).send(error.MANDATORY_FIELDS);
}
let data = await sequelize.daily_entry.findOne({
where: { id: req.params.id },
include: [
sequelize.report_data
]
});
let result = error.OK
result.data = data
logger.info(result);
return res.status(200).send(result);
}).catch(function (err) {
logger.warn(err)
console.log(err)
return res.status(500).send(error.SERVER_ERROR);
});
}
daily_entry table schema
module.exports = function (sequelize, DataTypes) {
const daily_entry = sequelize.define('daily_entry ', {
user_id: {
type: DataTypes.INTEGER(),
allowNull: true
},
date: {
type: DataTypes.STRING,
allowNull: true
},
report_status: {
type: DataTypes.STRING,
allowNull: true
},
high_close: {
type: DataTypes.DOUBLE(),
allowNull: true
},
high_open: {
type: DataTypes.DOUBLE(),
allowNull: true
},
low_close: {
type: DataTypes.DOUBLE(),
allowNull: true
},
low_open: {
type: DataTypes.DOUBLE(),
allowNull: true
},
is_active: {
type: DataTypes.BOOLEAN,
allowNull: true
}
});
return daily_entry
};
report_data tables schema
module.exports = function (sequelize, DataTypes) {
const report_data= sequelize.define('report_data', {
daily_entry : {
type: DataTypes.INTEGER(),
allowNull: true
},
Date: {
type: DataTypes.INTEGER(),
allowNull: true
},
report_document_id: {
type: DataTypes.TEXT,
allowNull: true
}
},
{
tableName: 'report_data'
});
return report_data
};
So, Where am I doing wrong and why I am getting entry_i as foreign key
Try To change your table name to CamelCase and then try.
I know this should be comment but at this time I don't have privilege of comment

Categories