getTotalAmount: (userId,products) => {
return new Promise(async(res,rej) => {
let total = await db.get().collection(collections.CART_COLLECTION).aggregate([
{
$match:{user: ObjectId(userId)}
},
{
$unwind:'$products'
},
{
$project:{
item: '$products.item',
quantity: '$products.quantity'
}
},
{
$lookup:{
from: collections.PRODUCT_COLLECTION,
localField: 'item',
foreignField: '_id',
as: 'product'
}
},
{
$project:{
item:1,quantity:1,product:{$arrayElemAt:["$product",0]}
}
},
{
$group: {
_id: null,
total: {
$sum: {
$cond: {
if: {$ifNull: [ "$product.OfferPrice", false ]},
then: {$multiply: [{ $toDecimal: '$quantity' }, {$convert: {input: {$ifNull: ["$product.OfferPrice", 0]}, to: "double"}}]},
else: {$multiply: [{ $toDecimal: '$quantity' }, {$convert: {input: { $ifNull: ["$product.Price", 0] }, to: "double"}}]}
}
}
}
}
}
]).toArray()
// console.log(total)
res(total[0].total)
})
callback(new error_1.MongoServerError(document));
^
MongoServerError: PlanExecutor error during aggregation :: caused by :: Failed to parse number '' in $convert with no onError value: Empty string
You can use the following to solve this issue -
{$convert: {input: "$product.Price", onNull: 0, to: "double"}}
Optionally, you can pass onError: 0 also as a safe check.
Reference - https://www.mongodb.com/docs/manual/reference/operator/aggregation/convert/
Related
in the shopping cart project, am trying to get the total amount in the cart but my aggregation method has some problems , how to fix this ?
error
callback(new error_1.MongoServerError(document));
^
MongoServerError: PlanExecutor error during aggregation :: caused by :: Failed to parse number '1,39,999' in $convert with no onError value: Did not consume whole string.
user_helpers.js this the aggregation
getTotalAmount:(userId)=>{
return new Promise(async(resolve,reject)=>{
let total=await db.get().collection(collection.CART_COLLECTION).aggregate([
{
$match:{user:objectId(userId)}
},
{
$unwind:'$products'
},{
$project:{
item:'$products.item',
quantity:'$products.quantity',
}
},
{
$lookup:{
from:collection.PRODUCT_COLLECTION,
localField:'item',
foreignField:'_id',
as:'product'
}
},
{
$project:{
item:1,quantity:1,product:{$arrayElemAt:['$product',0]}
}
},
{
$group:{
_id:null,
total:{$sum:{$multiply:[{ $toInt: '$quantity'},{ $toInt: '$product.Price' }]}} // my assumption , here comes the error
}
}
]).toArray()
resolve(total.length > 0 ? total[0].total: 0) // or here
})
}
user.js
// GET: view shopping cart contents
router.get('/cart',middleware.verifyLogin,async(req,res,next)=>{
try{
let user=req.session.user._id;
let products =await userHelpers.getCartProducts(req.session.user._id)
let totalValue=0
if(products.length>0){
totalValue=await userHelpers.getTotalAmount(req.session.user._id)
let proId=req.params.id
console.log('proId>>>>>>>>>>',proId);
}
console.log('products>',products)
console.log("user...",user);
res.render('user/cart',{products,user,totalValue,});
}catch (error) {
console.log(error);
}
})
It comes when you click the cart button error is getting ,
how to fix this ?
The error message says itself, your database contains strings like 1,39,999. When MongoDB tries to convert these to an integer, it fails because of the commas. So, before converting the string to an integer, you should remove all the commas and other non-numeric characters from the string. Like this:
db.collection.aggregate([
{
$match: {
user: ObjectId("userId433456666666666666")
}
},
{
$unwind: "$products"
},
{
$project: {
item: "$products.item",
quantity: "$products.quantity",
}
},
{
$lookup: {
from: "collection.PRODUCT_COLLECTION",
localField: "item",
foreignField: "_id",
as: "product"
}
},
{
$project: {
item: 1,
quantity: 1,
product: {
$arrayElemAt: [
"$product",
0
]
}
}
},
{
$group: {
_id: null,
total: {
$sum: {
$multiply: [
{
$toInt: '$quantity'
},
{
$toInt: {
"$replaceAll": {
"input": "$product.Price",
"find": ",",
"replacement": ""
}
}
}
]
}
}
}
}
]).toArray()
Here we are using $replaceAll to replace the commas with an empty string.
Hai I am new in nodejs and mongodb.I have to find the total price of a shopping cart.But when multiplying product quantity with price ,the price can not convert to number.when using parseInt result shows Nan.
Here is my code:
getTotalAmount: (userId) => {
return new Promise(async(resolve,reject)=>{
let total = await db.get().collection(collection.CART_COLLECTION).aggregate([
{
$match: { user: objectId(userId) }
},
{
$unwind: '$products'
},
{
$project: {
item: '$products.item',
quantity: '$products.quantity'
}
},
{
$lookup: {
from: collection.PRODUCT_COLLECTION,
localField: 'item',
foreignField: '_id',
as: 'product'
}
},
{
$project: {
_id: 1, item: 1, quantity: 1, product: { $arrayElemAt: ['$product', 0] }
}
},
{
$group:
{
_id:null,
total:{$sum:{$multiply:['$quantity',parseInt('$product.price')]}}
}
}
]).toArray()
console.log(total)
resolve(total)
}
)
}
result showing:
[ { _id: null, total: NaN } ]
You can convert a string to a number using the $convert operator
I've been pulling my hair out for weeks over this one.
I have a collection (this is a cut down version):
const SubscriberSchema = new Schema({
publication: { type: Schema.Types.ObjectId, ref: "publicationcollection" },
buyer: { type: Schema.Types.ObjectId, ref: "buyercollection" },
postCode: { type: String },
modifiedBy: { type: String },
modified: { type: Date }
});
I also have a collection containing the 1.75 million UK Postcodes
const PostcodeSchema = new Schema({
postcode: { type: String }
});
What I want to do is to return any record in the Subscriber collection which doesn't exist within the Postcode collection.
When I try a very simple aggregation using Mongoose on anything >100 records in the Subscriber collection, I'm getting either a timeout or a >16MB return error.
Here's what I've tried so far:
router.get(
"/badpostcodes/:id",
passport.authenticate("jwt", { session: false }),
(req, res) => {
const errors = {};
Subscriber.aggregate([
{
$match: {
publication: mongoose.Types.ObjectId(req.params.id),
postCode: { "$ne": null, $exists: true }
}
},
{
$lookup: {
'from': 'postcodescollections',
'localField': 'postCode',
'foreignField': 'postcode',
'as': 'founditem'
}
},
// {
// $unwind: '$founditem'
// },
{
$match: {
'founditem': { $eq: [] }
}
}
], function (err, result) {
if (err) {
console.log(err);
} else {
if (result.length > 0) {
res.json(result);
} else {
res.json("0");
}
}
})
}
);
The unwind didn't seem to do anything but it's commented out to show I tried to use it.
I've also tried using a pipeline on the lookup instead but that didn't work, similar to the following (sorry, I don't have my original code attempt so this is from memory only):
$lookup: {
'from': 'postcodescollections',
'let': { 'postcode': "$postCode" },
'pipeline': [
{
'$match': {
'postcode': { $exists: false }
}
},
{
'$unwind': "$postCode"
}
],
'as': 'founditem'
}
Thanks in advance so I can hopefully retain some hair!
You are doing a match on all postcodes that don't match and then unwinding those - that will be a 1.75m documents for each subscriber! The syntax in $lookup is also incorrect I think.
I think you can try something like the following - adjust accordingly for your data:
Do a $lookup to find a matching postcode in postcodes, then do a match to filter those subscribers that that don't have any founditem elements: "founditem.0": {$exists: false}
See an example:
db.getCollection("subscribers").aggregate(
[
// Stage 1
{
$match: {
postCode: { "$ne": null, $exists: true }
}
},
// Stage 2
{
$project: {
_id: 1,
postCode: 1
}
},
// Stage 3
{
$lookup: {
from: "postcodescollections",
let: { p: "$postCode" },
pipeline: [
{
$match: {
$expr:
{
$eq: ["$$p","$postcode"] }
}
},
{ $project: { _id: 1 } }
],
as: "founditem"
}
},
// Stage 4
{
$match: {
"founditem.0": {$exists: false}
}
},
]
);
I have 4 collections for store order data.
1. order => field => _id, order_no, cust_id, order_date
2. order_address => field => _id, order_id, cust_name, mobile, address
3. order_details => field => _id, order_id, product_id, seller_id, qty, price
4. order_payment => field => _id, payment_type, payment_status
in that order_details collection has n number of record for a number of product in one order.
in that how to get particular seller order from my data using aggregate in node.js from MongoDB database
i try this code but it's show ordre_details = [] but show order in my result:
var query = [
{ "$lookup": {
from: 'order_details',
let: { order_id: "$_id" },
pipeline: [
{ $match: { $expr: { $and: [{ $eq: [ "$order_id", "$$order_id" ] }, { $eq: [ "$seller_id", ObjectID(seller_id) ] }] } } },
{ $project: {
amount: 1,
cod_charge: 1,
shipping_charge: 1,
pid: 1,
product_attribute_id: 1,
qty: 1
} },
{ "$lookup": {
from: 'product',
let: { product_id: "$pid", product_attribute_id: '$product_attribute_id'},
pipeline: [
{ $match: { $expr: { $eq: [ "$_id", "$$product_id" ] } } },
{ $project: { _id: 1, name: 1, sku: 1 } },
{ "$lookup": {
from: 'product_image',
let: { product_attribute_id: '$$product_attribute_id' },
pipeline: [
{ $match: { $expr: { $eq: [ "$product_attribute_id", "$$product_attribute_id" ] } } },
{ $project: { _id: 0, image: 1, is_default: 1 } },
{ $sort : { is_default: -1 } },
{ $replaceRoot: { newRoot: {_id: "$_id", image: "$image" } } }
],
as: 'product_image'
} },
{ $replaceRoot: { newRoot: {
_id: "$_id",
name: "$name",
sku: "$sku",
image: { $arrayElemAt: [ "$product_image.image", 0 ] }
} } }
],
as: 'product'
} },
{ "$replaceRoot": { newRoot: {
_id: '$$ROOT._id',
pid: '$$ROOT.pid',
amount: '$$ROOT.amount',
cod_charge: '$$ROOT.cod_charge',
shipping_charge: '$$ROOT.shipping_charge',
product_attribute_id: "$$ROOT.product_attribute_id",
qty: "$$ROOT.qty",
product: { $arrayElemAt: [ "$product", 0 ] },
} } },
],
as: 'order_details'
} },
{ "$replaceRoot": {
newRoot: {
_id: "$_id",
order_no: "$order_no",
cust_id: "$cust_id",
order_date: "$order_date",
order_details: "$order_details"
}
} }
]
orderModel.order.aggregate(query, function(err, orderData){})
We currently have the following code to group all documents from a collection by creation date:
this.aggregate( [
{ $match: { language: options.criteria.language, status: 1, type:{ $ne: "challenge" } }},
{ $group: {
_id: {
y: { '$year': '$created' },
m: { '$month': '$created' },
d: { '$dayOfMonth': '$created' },
h: { '$hour': '$created' },
min: { '$minute': '$created' },
s: { '$second': '$created' }
},
count: { $sum : 1 }
}},
{$project: {
date: "$_id", // so this is the shorter way
count: 1,
_id: 0
}},
{ $sort: { "date": 1 } }
], function(err, result){
if(err) {
return callback(err);
}
callback(null, result);
});
However, we now would like to group the results based on the start date instead of the creation date. The start date is not a field of the current collection, but it is a field of the currentRevision object, that is linked in this collection.
I tried this:
this.aggregate( [
{ $match: { language: options.criteria.language, status: 1, type:{ $ne: "challenge" } }},
{ $group: {
_id: {
y: { '$year': '$currentRevision.start_date' },
m: { '$month': '$currentRevision.start_date' },
d: { '$dayOfMonth': '$currentRevision.start_date' },
h: { '$hour': '$currentRevision.start_date' },
min: { '$minute': '$currentRevision.start_date' },
s: { '$second': '$currentRevision.start_date' }
},
count: { $sum : 1 }
}},
{$project: {
date: "$_id", // so this is the shorter way
count: 1,
_id: 0
}},
{ $sort: { "date": 1 } }
], function(err, result){
if(err) {
return callback(err);
}
callback(null, result);
});
but that just gives me an error: "failed to query db"
any idea on how to solve this?