nodejs mongodb findAndModify exception: E11000 duplicate key error index - node.js

monogodb databse:
{ "title" : "A vs B ha",
"status" : 1,
"items" : [
{ "name" : "0",
"num" : 0,
"men" : [
{ "user" : "id1",
"score" : 300 },
{ "user" : "id2",
"score" : 1300 },
{ "user" : "id3",
"score" : 400 } ] },
{ "name" : "1",
"num" : 0,
"men" : [
{ "user" : "id11",
"score" : 3300 },
{ "user" : "id23",
"score" : 13400 },
{ "user" : "id3",
"score" : 4000 } ] },
{ "name" : "2",
"num" : 0,
"men" : [] } ],
"_id" : ObjectId( "538db59fa332f765c0f2c210" ) }
This Node.js code doesn't work:
collection.findAndModify(
{"_id": idSearch
,"items.name":sBetItem,"items.men.user":sUser}
,[]
, {
$set:{
"items.men.user":sUser}
,$inc: { "items.men.score": sScore }
}
, {new:true, upsert:true}
,function(err, docUser) {
if (err){
console.warn(err.message); // returns error if no matching object found
}else{
console.dir(docUser);
}
});
I want to search a player's score, if it doesn't exist, insert new;
if it already exist, increase his score number.
But it has error:exception: E11000 duplicate key error index

Related

Mongo: filter documents from multiple collections and merge

I am new to mongo and NodeJS and have a use case where I want to get filtered results from multiple collection.
Advance apologies for the long post.
for ex:
collectionA
{
"_id" : "foo#gmail.com",
"name" : "Foo",
"location" : {
"coordinates" : [
-122.420170,
37.780080
],
"type" : "Point"
}
},
{
"_id" : "bar#gmail.com,
"name" : "Bar",
"location" : {
"coordinates" : [
-122.420060,
37.780180
],
"type" : "Point"
}
}
collectionB: Some attributes are not present for all the documents and hence optional
{
"_id" : "foo#gmail.com"
"AttributeA" : [
{
"name" : "AttA_Name",
"val" : "Coll_B_AttA_Val_Foo"
},
{
"name" : "AttA_Name1",
"val" : "Coll_B_AttA_Val_Foo"
}]
},
{
"_id" : "bar#gmail.com"
"AttributeA" : [
{
"name" : "AttA_Name",
"val" : "Coll_B_AttA_Val_Bar"
},
{
"name" : "AttA_Name2",
"val" : "Coll_B_AttA_Val_Bar"
}
],
"AttributeB" : [
{
"name" : "AttB_Name",
"val" : "Coll_B_AttB_Val_Bar"
}
]
}
CollectionC: Some attributes are not present for all the documents and hence optional
{
"_id" : "foo#gmail.com"
"AttributeA" : [
{
"name" : "Coll_C_AttA_Name",
"val" : "Coll_C_AttA_Val_Foo"
}]
},
{
"_id" : "bar#gmail.com"
"AttributeA" : [
{
"name" : "Coll_C_AttA_Name",
"val" : "Coll_C_AttA_Val_Bar"
}
],
"AttributeB" : [
{
"name" : "Coll_C_AttB_Name",
"val" : "Coll_C_AttB_Val_Bar"
}
]
}
I know Collection B and C schema looks the same but the purpose is different and they have to be different. DB design is not the question so I would appreciate if do not put all the focus on it.
Query:
Assume there is another user (Alan) with same attributes present as Bar that exist in the collection but is not living nearby the location of Bar.
The query I am trying to build on top of these is,
Find people living nearby from CollectionA
And Collection B, if AttributeA exist and have an element with name: AttA_Name
And in Collection C, if AttributeA exist and have an name: Coll_C_AttA_Name
In the above case I am expecting a result as
{
"_id" : "foo#gmail.com",
"name" : "Foo",
"location" : {
"coordinates" : [
-122.420170,
37.780080
],
"type" : "Point"
},
"collectionB_AttributeA" : [
{
"name" : "AttA_Name",
"val" : "Coll_B_AttA_Val_Foo"
},
{
"name" : "AttA_Name1",
"val" : "Coll_B_AttA_Val_Foo"
}]
,
"collectionC_AttributeA" : [
{
"name" : "Coll_C_AttA_Name",
"val" : "Coll_C_AttA_Val_Foo"
}]
},
{
"_id" : "bar#gmail.com,
"name" : "Bar",
"location" : {
"coordinates" : [
-122.420060,
37.780180
],
"type" : "Point"
},
"collectionB_AttributeA":[
{
"name" : "AttA_Name",
"val" : "Coll_B_AttA_Val_Bar"
},
{
"name" : "AttA_Name2",
"val" : "Coll_B_AttA_Val_Bar"
}
],
"collectionC_AttributeA":[
{
"name" : "Coll_C_AttA_Name",
"val" : "Coll_C_AttA_Val_Bar"
}
]
}
There is one way of doing is in parts:
query Collection A and get the nearby people
Loop through the result of 1 and find in CollectionB if they have AttributeA and an element with name AttA_Name and eliminate if they don't match.
Loop through the filtered results from 2 and find in CollectionC if they have AttributeA and and element with name Coll_C_AttA_Name and if they don't eliminate such documents.
Is there a way I can use aggregate to build this query as one? I tried reading and trying the aggregate but seems like my understanding is incomplete.
let result = await CollectionASchema.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [ Number(long) , Number(lat) ] },
distanceField: "dist.calculated",
minDistance: 0,
maxDistance: radiusinmetres,
spherical: true
}
},
{
$lookup:
{
from: 'collectionB',
pipeline: [
{ $match : { $and: [{ AttributeA :{$exists: true}}, { [category]: { $elemMatch: { name: “AttA_Name” } } }] }},
{ $project: { AttributeA: 0 } }
],
as: "collectionB_AttributeA"
}
}
])
If you can explain if this is possible or let me know off this is the right approach that would be helpful.

Query Mongodb works with the terminal but not with node js

I find myself in front of a problem that I do not know how to solve.
The purpose of the query:
Compare the document of the selection person, and the one who requests the query if the id of the person selected is present in friend then is_friend will be equal to true otherwise it will be equal to false.
I got this query:
users.aggregate({
$match:{
search:/f/
}},{
$lookup:
{from:"users", let:{user:"$_id"}, pipeline:[{
$match:{
$expr:{
$and:[{
$in:["$$user", "$friend.id"]},{
$eq:["$_id", ObjectId("5bd22f28f77cfb1f6ce503ca")]
}]
}
}
},
{$limit:1},
{$project:{email:0, password:0}}
], as:"is_friend"}},{
$project:{name:1, search:1, desc:1, color:1, profil:1, banner:1, date:1, friend:1, is_friend:{
$cond:{
if:{
$eq:[{$arrayElemAt:["$is_friend",0]}, undefined]
},
then: "false",
else:"true"
}
}
}
})
So there is 1 document of users:
{
"_id" : ObjectId("5bd22f28f77cfb1f6ce503ca"),
"search" : "flarize",
"name" : "flarize",
"email" : "flarize.73#gmail.com",
"password" : "$2a$10$eYeOtEkEUyD7TFkjKvhZOuSSpvBolkL17TrPHuoHhOT8JrsQR0UKW",
"color" : 0,
"profil" : "",
"banner" : "",
"desc" : "",
"date" : 1540501286109,
"friend" : [
{
"id" : ObjectId("5bd19a92da24674fdabd26b6"),
"date" : 1540676931288
},
{
"id" : ObjectId("5bd22f28f77cfb1f6ce503ca"),
"date" : 1540676931288
}
]
}
When I call this request in the terminal i got this result:
{
"_id" : ObjectId("5bd22f28f77cfb1f6ce503ca"),
"search" : "flarize",
"name" : "flarize",
"color" : 0,
"profil" : "",
"banner" : "",
"desc" : "",
"date" : 1540501286109,
"friend" : [
{
"id" : ObjectId("5bd19a92da24674fdabd26b6"),
"date" : 1540666689579
},
{
"id" : ObjectId("5bd22f28f77cfb1f6ce503ca"),
"date" : 1540666689579
}
],
"is_friends" : "true"
}
That's the result I want.
But the node js i got this :
{
"_id" : ObjectId("5bd22f28f77cfb1f6ce503ca"),
"search" : "flarize",
"name" : "flarize",
"color" : 0,
"profil" : "",
"banner" : "",
"desc" : "",
"date" : 1540501286109,
"friend" : [
{
"id" : ObjectId("5bd19a92da24674fdabd26b6"),
"date" : 1540666689579
},
{
"id" : ObjectId("5bd22f28f77cfb1f6ce503ca"),
"date" : 1540666689579
}
],
is_friend : {
"_id" : ObjectId("5bd22f28f77cfb1f6ce503ca"),
"search" : "flarize",
"name" : "flarize",
"color" : 0,
"profil" : "",
"banner" : "",
"desc" : "",
"date" : 1540501286109,
"friend" : [
{
"id" : ObjectId("5bd19a92da24674fdabd26b6"),
"date" : 1540676931288
},
{
"id" : ObjectId("5bd22f28f77cfb1f6ce503ca"),
"date" : 1540676931288
}
]
}
}
How to solve the problem.
EDIT
mu node js code:
users.aggregate({
$match:{
search:new RegExp(req.body.search, 'i')
}},{
$lookup:
{from:"users", let:{user:"$_id"}, pipeline:[{
$match:{
$expr:{
$and:[{
$in:["$$user", "$friend.id"]},{
$eq:["$_id", new ObjectId(decoded["_id"])]
}]
}
}
},
{$limit:1},
{$project:{email:0, password:0}}
], as:"is_friend"}},{
$project:{name:1, search:1, desc:1, color:1, profil:1, banner:1, date:1, friend:1, is_friend:{
$cond:{
if:{
$eq:[{$arrayElemAt:["$is_friend",0]}, undefined]
},
then: "false",
else:"true"
}
}
}
}).toArray(function(err, result){
if(err) throw err;
ress.send(result);
});
Thank you for helping me

How to count the number of values found for a field in MongoDB?

I have to find "exitState" : this is single document , if multiple documents how to find.
{
"_id" : "abc",
"exitType" : "Hang",
"exitState" : "INDIA",
"outcome" : "Successful",
"CEV" : [
{
"LogID" : "CEV",
"ReportingMode" : "N",
"Log_DateTime" : "02:23:2016 00:17:48:913",
"Log_TS" : NumberLong(1456186668913),
"ServiceType" : "TEL",
"MsgID" : "25000",
"SysName" : "test123",
"ProcessID" : "9611",
"Port" : "0",
"ModuleName" : "ArcCDR::CDR_CustomEvent",
"AppName" : "testVXML2",
"MsgTxt" : "abc::24::Test::outcome=Successful$$$exitType=Hang$$$exitState=INDIA",
"Record_Key" : "abc",
"Token1" : "24",
"CustomerName" : "Test",
"CEV_MsgTxt" : "outcome=Successful$$$exitType=Hang$$$exitState=INDIA",
"outcome" : "Successful",
"exitType" : "Hang",
"exitState" : "INDIA"
}
],
"language" : "ENGLISH",
"SC_TS" : ISODate("2016-02-23T00:17:06.060+0000"),
"SC_TimeMS" : NumberLong(1456186626060),
"CDR_SC" : {
"LogID" : "CDR",
"ReportingMode" : "N",
"Log_DateTime" : "02:23:2016 00:17:06:060",
"Log_TS" : NumberLong(1456186626060),
"ServiceType" : "TEL",
"MsgID" : "20010",
"SysName" : "test123",
"ProcessID" : "9611",
"Port" : "0",
"ModuleName" : "TEL_AnswerCall",
"AppName" : "testVXML2",
"MsgTxt" : "abc:SC:testVXML2:452:607856:0223201600170606::",
"Record_Key" : "abc",
"CDR_Type" : "SC",
"Token2" : "testVXML2",
"Token3" : "452",
"Token4" : "607856",
"Token5" : "0223201600170606"
},
" SC_TS_TZ" : ISODate("2016-02-23T00:17:06.060+0000"),
"EC_TS" : ISODate("2016-02-23T00:17:48.910+0000"),
"EC_TS_TZ" : ISODate("2016-02-23T00:17:48.910+0000"),
"EC_TimeMS" : NumberLong(1456186668910),
"CDR_EC" : {
"LogID" : "CDR",
"ReportingMode" : "N",
"Log_DateTime" : "02:23:2016 00:17:48:910",
"Log_TS" : NumberLong(1456186668910),
"ServiceType" : "TEL",
"MsgID" : "20011",
"SysName" : "test123",
"ProcessID" : "9611",
"Port" : "0",
"ModuleName" : "TEL_SRRecognizeV2",
"AppName" : "testVXML2",
"MsgTxt" : "abc:EC:02:0223201600174891::",
"Record_Key" : "abc",
"CDR_Type" : "EC",
"Token2" : "02",
"Token3" : "0223201600174891"
},
"CustomerName" : "Test"
}
Below is my query but unable to find exitState in all documents . Can you please?
dbo.ProductModel.aggregate([
{$match: {"EC_TS":{$gte:new Date(start.toISOString()), $lte:new Date(end.toISOString())}} },
{$group:
{_id: '$exitState', count : {$sum: 1} }
}
]).toArray(function(err, result4) {
console.log(+ result4[0]["exitState"]);
console.log("Total exitState=" + result4[0]["total"]);
q4result=(result4[0]["total"]);
});
});
Maybe you can filter the results:
const result5 = result4.filter((result) => result.exitState && result.exitState !== '');
const nbResults = result5.length;
db.tablename.find({},{"exitStates":1}).count()
https://www.w3resource.com/mongodb-exercises/mongodb-exercise-4.php
I can't understand what is your question exactly. if you want to know how many docs exist in the collection and count them by their exitState, this function retuns what you want. I don't know $match works like this or not, But please log the result for test before doing any action on it.
dbo.ProductModel.aggregate([
{ $match: { "EC_TS": { $gte: new Date( start.toISOString() ),
$lte: new Date( end.toISOString() ) } } },
{ $group: {_id: '$exitState', count : {$sum: 1} } }
], (err, result) => {
if (err) throw err;
console.log(result);
// result is like this:
// [ {"_id": "INDIA", "count": 3}, {"_id": "US", "count": 8} ]
});

Mongo pull object from array inside array

i have inside my mongoDB collection this document
{
"_id" : ObjectId("5b633025579fac22e74bf3be"),
"FLAGS" : [
{
"toSent" : [
{
"_id" : ObjectId("5b633025579fac22e74bf3c2"),
"phone" : "+84404040404"
},
{
"_id" : ObjectId("5b633025579fac22e74bf3c1"),
"phone" : "+212652253403"
},
{
"_id" : ObjectId("5b633025579fac22e74bf3c0"),
"phone" : "+212123456788"
}
],
"_id" : ObjectId("5b633025579fac22e74bf3bf"),
"action" : "group_p_a"
},
{
"toSent" : [
{
"_id" : ObjectId("5b633031579fac22e74bf3c9"),
"phone" : "+212651077199"
},
{
"_id" : ObjectId("5b633031579fac22e74bf3c8"),
"phone" : "+84404040404"
},
{
"_id" : ObjectId("5b633031579fac22e74bf3c7"),
"phone" : "+212652253403"
},
{
"_id" : ObjectId("5b633031579fac22e74bf3c6"),
"phone" : "+212123456788"
}
],
"_id" : ObjectId("5b633031579fac22e74bf3c5"),
"action" : "group_p_a"
}
],
"time" : ISODate("2018-08-02T16:24:05.747+0000"),
"action_user_phone" : "+212123456788",
"idGroup" : "e534379a-1580-4568-b5ec-6eaf981538d2",
"nomGroup" : "MOH FOR EVER",
"__v" : NumberInt(0)
}
TODO
I need to remove for example this element { "_id" : ObjectId("5b633025579fac22e74bf3c2"), "phone" : "+84404040404"}
WHAT I DID
GroupEvents.update({}, {$pull:{FLAGS:{$elemMatch:{toSent:{phone: "+84404040404"} }}}},function(err,ret){
if(err)
console.log("error"+err);
if(ret)
console.log(ret);
});
It remove all what's inside toSent event if it doesn't match.
Any help please
You need to use $ positional operator instead of $elemMatch here
GroupEvents.update(
{ "Flags.toSent.phone": "+84404040404" },
{ "$pull": { "FLAGS.$.toSent": { "phone": "+84404040404" }}},
)
If you want remove from every element of FLAGS array this you need to use $[] the all positional operator
GroupEvents.update(
{ "Flags.toSent.phone": "+84404040404" },
{ "$pull": { "FLAGS.$[].toSent": { "phone": "+84404040404" }}},
)

Need to apply two group in sequence and second group should will have effect on result of first group

I want to group my data on the base of factoryId field and then each factory there will be multiple orders want to again group on basis of orderId as each order can contain multiple items. Here I am giving the example of my data and what I need and first group by which I tried.
{
"_id" : ObjectId("5b3e270c42d8004cea382e87"),
"factoryId" : ObjectId("5aa76190cef23a1561b8056c"),
"productId" : ObjectId("5aa78c66cef23a1561b80893"),
"orderId" : ObjectId("5b3e270c42d8004cea382e86"),
"generatedOrderId" : "3985-166770-4554",
"productName" : "Lakme Lotion"
},
{
"_id" : ObjectId("5b3e270c42d8004cea382e88"),
"factoryId" : ObjectId("5b39aed32832f72062e51c23"),
"productId" : ObjectId("5b3cb96139cec8341df52c4b"),
"orderId" : ObjectId("5b3e270c42d8004cea382e86"),
"generatedOrderId" : "3985-166770-4554",
"productName" : "Coke"
},
{
"_id" : ObjectId("5b3e27b07fe0d94d62b76b2a"),
"factoryId" : ObjectId("5aa76190cef23a1561b8057c"),
"productId" : ObjectId("5ac21075ac347a5fbf355028"),
"orderId" : ObjectId("5b3e27b07fe0d94d62b76b27"),
"generatedOrderId" : "3985-755507-7484",
"productName" : "Spoon"
}
And I want result as:
{
"factoryId":ObjectId("5aa76190cef23a1561b8057c"),
"orders":[
{
"orderId":ObjectId("5b3e270c42d8004cea382e86")
"items":[
{
"productName":"Lakme Lotion"
},
{
"productName":"Coke"
}
]
}
]
}
Can anyone help me with this?. Any help is appreciated.
I tried and It worked for me. Sorry
db.getCollection("transactions").aggregate(
[
{
"$group" : {
"_id" : "$orderId",
"items" : {
"$push" : "$$ROOT"
}
}
},
{
"$project" : {
"orderId" : "$_id",
"items" : "$items",
"_id" : 0
}
},
{
"$unwind" : {
"path" : "$items",
"preserveNullAndEmptyArrays" : false
}
},
{
"$group" : {
"_id" : "$items.factoryId",
"orders" : {
"$push" : "$$ROOT"
}
}
},
{
"$project" : {
"factoryId" : "$_id",
"orders" : "$orders",
"_id" : 0
}
}
]
);

Resources