Moongoose aggregate $match does not match id's
up vote
9
down vote
favorite
I want to show products by ids (56e641d4864e5b780bb992c6
and 56e65504a323ee0812e511f2
) and show price after subtracted by discount if available.
I can count the final price using aggregate, but this return all document in a collection, how to make it return only the matches ids
"_id" : ObjectId("56e641d4864e5b780bb992c6"),
"title" : "Keyboard",
"discount" : NumberInt(10),
"price" : NumberInt(1000)
"_id" : ObjectId("56e65504a323ee0812e511f2"),
"title" : "Mouse",
"discount" : NumberInt(0),
"price" : NumberInt(1000)
"_id" : ObjectId("56d90714a48d2eb40cc601a5"),
"title" : "Speaker",
"discount" : NumberInt(10),
"price" : NumberInt(1000)
this is my query
productModel.aggregate([
{
$project: {
title : 1,
price: {
$cond: {
if: {$gt: ["$discount", 0]}, then: {$subtract: ["$price", {$divide: [{$multiply: ["$price", "$discount"]}, 100]}]}, else: "$price"
}
}
}
}
], function(err, docs){
if (err){
console.log(err)
}else{
console.log(docs)
}
})
and if i add this $in
query, it returns empty array
productModel.aggregate([
{
$match: {_id: {$in: ids}}
},
{
$project: {
title : 1,
price: {
$cond: {
if: {$gt: ["$discount", 0]}, then: {$subtract: ["$price", {$divide: [{$multiply: ["$price", "$discount"]}, 100]}]}, else: "$price"
}
}
}
}
], function(err, docs){
if (err){
console.log(err)
}else{
console.log(docs)
}
})
mongodb mongoose mongodb-query aggregation-framework
add a comment |
up vote
9
down vote
favorite
I want to show products by ids (56e641d4864e5b780bb992c6
and 56e65504a323ee0812e511f2
) and show price after subtracted by discount if available.
I can count the final price using aggregate, but this return all document in a collection, how to make it return only the matches ids
"_id" : ObjectId("56e641d4864e5b780bb992c6"),
"title" : "Keyboard",
"discount" : NumberInt(10),
"price" : NumberInt(1000)
"_id" : ObjectId("56e65504a323ee0812e511f2"),
"title" : "Mouse",
"discount" : NumberInt(0),
"price" : NumberInt(1000)
"_id" : ObjectId("56d90714a48d2eb40cc601a5"),
"title" : "Speaker",
"discount" : NumberInt(10),
"price" : NumberInt(1000)
this is my query
productModel.aggregate([
{
$project: {
title : 1,
price: {
$cond: {
if: {$gt: ["$discount", 0]}, then: {$subtract: ["$price", {$divide: [{$multiply: ["$price", "$discount"]}, 100]}]}, else: "$price"
}
}
}
}
], function(err, docs){
if (err){
console.log(err)
}else{
console.log(docs)
}
})
and if i add this $in
query, it returns empty array
productModel.aggregate([
{
$match: {_id: {$in: ids}}
},
{
$project: {
title : 1,
price: {
$cond: {
if: {$gt: ["$discount", 0]}, then: {$subtract: ["$price", {$divide: [{$multiply: ["$price", "$discount"]}, 100]}]}, else: "$price"
}
}
}
}
], function(err, docs){
if (err){
console.log(err)
}else{
console.log(docs)
}
})
mongodb mongoose mongodb-query aggregation-framework
add a comment |
up vote
9
down vote
favorite
up vote
9
down vote
favorite
I want to show products by ids (56e641d4864e5b780bb992c6
and 56e65504a323ee0812e511f2
) and show price after subtracted by discount if available.
I can count the final price using aggregate, but this return all document in a collection, how to make it return only the matches ids
"_id" : ObjectId("56e641d4864e5b780bb992c6"),
"title" : "Keyboard",
"discount" : NumberInt(10),
"price" : NumberInt(1000)
"_id" : ObjectId("56e65504a323ee0812e511f2"),
"title" : "Mouse",
"discount" : NumberInt(0),
"price" : NumberInt(1000)
"_id" : ObjectId("56d90714a48d2eb40cc601a5"),
"title" : "Speaker",
"discount" : NumberInt(10),
"price" : NumberInt(1000)
this is my query
productModel.aggregate([
{
$project: {
title : 1,
price: {
$cond: {
if: {$gt: ["$discount", 0]}, then: {$subtract: ["$price", {$divide: [{$multiply: ["$price", "$discount"]}, 100]}]}, else: "$price"
}
}
}
}
], function(err, docs){
if (err){
console.log(err)
}else{
console.log(docs)
}
})
and if i add this $in
query, it returns empty array
productModel.aggregate([
{
$match: {_id: {$in: ids}}
},
{
$project: {
title : 1,
price: {
$cond: {
if: {$gt: ["$discount", 0]}, then: {$subtract: ["$price", {$divide: [{$multiply: ["$price", "$discount"]}, 100]}]}, else: "$price"
}
}
}
}
], function(err, docs){
if (err){
console.log(err)
}else{
console.log(docs)
}
})
mongodb mongoose mongodb-query aggregation-framework
I want to show products by ids (56e641d4864e5b780bb992c6
and 56e65504a323ee0812e511f2
) and show price after subtracted by discount if available.
I can count the final price using aggregate, but this return all document in a collection, how to make it return only the matches ids
"_id" : ObjectId("56e641d4864e5b780bb992c6"),
"title" : "Keyboard",
"discount" : NumberInt(10),
"price" : NumberInt(1000)
"_id" : ObjectId("56e65504a323ee0812e511f2"),
"title" : "Mouse",
"discount" : NumberInt(0),
"price" : NumberInt(1000)
"_id" : ObjectId("56d90714a48d2eb40cc601a5"),
"title" : "Speaker",
"discount" : NumberInt(10),
"price" : NumberInt(1000)
this is my query
productModel.aggregate([
{
$project: {
title : 1,
price: {
$cond: {
if: {$gt: ["$discount", 0]}, then: {$subtract: ["$price", {$divide: [{$multiply: ["$price", "$discount"]}, 100]}]}, else: "$price"
}
}
}
}
], function(err, docs){
if (err){
console.log(err)
}else{
console.log(docs)
}
})
and if i add this $in
query, it returns empty array
productModel.aggregate([
{
$match: {_id: {$in: ids}}
},
{
$project: {
title : 1,
price: {
$cond: {
if: {$gt: ["$discount", 0]}, then: {$subtract: ["$price", {$divide: [{$multiply: ["$price", "$discount"]}, 100]}]}, else: "$price"
}
}
}
}
], function(err, docs){
if (err){
console.log(err)
}else{
console.log(docs)
}
})
mongodb mongoose mongodb-query aggregation-framework
mongodb mongoose mongodb-query aggregation-framework
edited Mar 24 '16 at 4:52
Blakes Seven
33.3k76072
33.3k76072
asked Mar 24 '16 at 4:27
Muhammad Fasalir Rahman
7319
7319
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
up vote
24
down vote
accepted
Your ids
variable will be constructed of "strings", and not ObjectId
values.
Mongoose "autocasts" string values for ObjectId
into their correct type in regular queries, but this does not happen in the aggregation pipeline, as in described in issue #1399.
Instead you must do the correct casting to type manually:
ids = ids.map(function(el) { return mongoose.Types.ObjectId(el) })
Then you can use them in your pipeline stage:
{ "$match": { "_id": { "$in": ids } } }
The reason is because aggregation pipelines "typically" alter the document structure, and therefore mongoose makes no presumption that the "schema" applies to the document in any given pipeline stage.
It is arguable that the "first" pipeline stage when it is a $match
stage should do this, since indeed the document is not altered. But right now this is not how it happens.
Any values that may possibly be "strings" or at least not the correct BSON type need to be manually cast in order to match.
That's it, it now works. but usually i throw the id as string in findOneAndUpdate or other query, and it works fine, is the problem only happen in aggregate?
– Muhammad Fasalir Rahman
Mar 24 '16 at 4:59
1
@MuhammadFasalirRahman This is exactly what I answered with. A.find()
can use theSchema
which of course has a default type ofObjectId
for the_id
field. Aggregation pipelines do not use theSchema
, as I actually already explained.
– Blakes Seven
Mar 24 '16 at 5:06
This is not working in mongoose 5
– Mina Luke
Feb 28 at 1:28
took me three days to get here; sigh.. I created a lamda inside my schema static methodconst castUserId = (userId) => mongoose.Types.ObjectId(userId)
now i'm happy
– timebandit
Jun 19 at 17:23
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
24
down vote
accepted
Your ids
variable will be constructed of "strings", and not ObjectId
values.
Mongoose "autocasts" string values for ObjectId
into their correct type in regular queries, but this does not happen in the aggregation pipeline, as in described in issue #1399.
Instead you must do the correct casting to type manually:
ids = ids.map(function(el) { return mongoose.Types.ObjectId(el) })
Then you can use them in your pipeline stage:
{ "$match": { "_id": { "$in": ids } } }
The reason is because aggregation pipelines "typically" alter the document structure, and therefore mongoose makes no presumption that the "schema" applies to the document in any given pipeline stage.
It is arguable that the "first" pipeline stage when it is a $match
stage should do this, since indeed the document is not altered. But right now this is not how it happens.
Any values that may possibly be "strings" or at least not the correct BSON type need to be manually cast in order to match.
That's it, it now works. but usually i throw the id as string in findOneAndUpdate or other query, and it works fine, is the problem only happen in aggregate?
– Muhammad Fasalir Rahman
Mar 24 '16 at 4:59
1
@MuhammadFasalirRahman This is exactly what I answered with. A.find()
can use theSchema
which of course has a default type ofObjectId
for the_id
field. Aggregation pipelines do not use theSchema
, as I actually already explained.
– Blakes Seven
Mar 24 '16 at 5:06
This is not working in mongoose 5
– Mina Luke
Feb 28 at 1:28
took me three days to get here; sigh.. I created a lamda inside my schema static methodconst castUserId = (userId) => mongoose.Types.ObjectId(userId)
now i'm happy
– timebandit
Jun 19 at 17:23
add a comment |
up vote
24
down vote
accepted
Your ids
variable will be constructed of "strings", and not ObjectId
values.
Mongoose "autocasts" string values for ObjectId
into their correct type in regular queries, but this does not happen in the aggregation pipeline, as in described in issue #1399.
Instead you must do the correct casting to type manually:
ids = ids.map(function(el) { return mongoose.Types.ObjectId(el) })
Then you can use them in your pipeline stage:
{ "$match": { "_id": { "$in": ids } } }
The reason is because aggregation pipelines "typically" alter the document structure, and therefore mongoose makes no presumption that the "schema" applies to the document in any given pipeline stage.
It is arguable that the "first" pipeline stage when it is a $match
stage should do this, since indeed the document is not altered. But right now this is not how it happens.
Any values that may possibly be "strings" or at least not the correct BSON type need to be manually cast in order to match.
That's it, it now works. but usually i throw the id as string in findOneAndUpdate or other query, and it works fine, is the problem only happen in aggregate?
– Muhammad Fasalir Rahman
Mar 24 '16 at 4:59
1
@MuhammadFasalirRahman This is exactly what I answered with. A.find()
can use theSchema
which of course has a default type ofObjectId
for the_id
field. Aggregation pipelines do not use theSchema
, as I actually already explained.
– Blakes Seven
Mar 24 '16 at 5:06
This is not working in mongoose 5
– Mina Luke
Feb 28 at 1:28
took me three days to get here; sigh.. I created a lamda inside my schema static methodconst castUserId = (userId) => mongoose.Types.ObjectId(userId)
now i'm happy
– timebandit
Jun 19 at 17:23
add a comment |
up vote
24
down vote
accepted
up vote
24
down vote
accepted
Your ids
variable will be constructed of "strings", and not ObjectId
values.
Mongoose "autocasts" string values for ObjectId
into their correct type in regular queries, but this does not happen in the aggregation pipeline, as in described in issue #1399.
Instead you must do the correct casting to type manually:
ids = ids.map(function(el) { return mongoose.Types.ObjectId(el) })
Then you can use them in your pipeline stage:
{ "$match": { "_id": { "$in": ids } } }
The reason is because aggregation pipelines "typically" alter the document structure, and therefore mongoose makes no presumption that the "schema" applies to the document in any given pipeline stage.
It is arguable that the "first" pipeline stage when it is a $match
stage should do this, since indeed the document is not altered. But right now this is not how it happens.
Any values that may possibly be "strings" or at least not the correct BSON type need to be manually cast in order to match.
Your ids
variable will be constructed of "strings", and not ObjectId
values.
Mongoose "autocasts" string values for ObjectId
into their correct type in regular queries, but this does not happen in the aggregation pipeline, as in described in issue #1399.
Instead you must do the correct casting to type manually:
ids = ids.map(function(el) { return mongoose.Types.ObjectId(el) })
Then you can use them in your pipeline stage:
{ "$match": { "_id": { "$in": ids } } }
The reason is because aggregation pipelines "typically" alter the document structure, and therefore mongoose makes no presumption that the "schema" applies to the document in any given pipeline stage.
It is arguable that the "first" pipeline stage when it is a $match
stage should do this, since indeed the document is not altered. But right now this is not how it happens.
Any values that may possibly be "strings" or at least not the correct BSON type need to be manually cast in order to match.
answered Mar 24 '16 at 4:52
Blakes Seven
33.3k76072
33.3k76072
That's it, it now works. but usually i throw the id as string in findOneAndUpdate or other query, and it works fine, is the problem only happen in aggregate?
– Muhammad Fasalir Rahman
Mar 24 '16 at 4:59
1
@MuhammadFasalirRahman This is exactly what I answered with. A.find()
can use theSchema
which of course has a default type ofObjectId
for the_id
field. Aggregation pipelines do not use theSchema
, as I actually already explained.
– Blakes Seven
Mar 24 '16 at 5:06
This is not working in mongoose 5
– Mina Luke
Feb 28 at 1:28
took me three days to get here; sigh.. I created a lamda inside my schema static methodconst castUserId = (userId) => mongoose.Types.ObjectId(userId)
now i'm happy
– timebandit
Jun 19 at 17:23
add a comment |
That's it, it now works. but usually i throw the id as string in findOneAndUpdate or other query, and it works fine, is the problem only happen in aggregate?
– Muhammad Fasalir Rahman
Mar 24 '16 at 4:59
1
@MuhammadFasalirRahman This is exactly what I answered with. A.find()
can use theSchema
which of course has a default type ofObjectId
for the_id
field. Aggregation pipelines do not use theSchema
, as I actually already explained.
– Blakes Seven
Mar 24 '16 at 5:06
This is not working in mongoose 5
– Mina Luke
Feb 28 at 1:28
took me three days to get here; sigh.. I created a lamda inside my schema static methodconst castUserId = (userId) => mongoose.Types.ObjectId(userId)
now i'm happy
– timebandit
Jun 19 at 17:23
That's it, it now works. but usually i throw the id as string in findOneAndUpdate or other query, and it works fine, is the problem only happen in aggregate?
– Muhammad Fasalir Rahman
Mar 24 '16 at 4:59
That's it, it now works. but usually i throw the id as string in findOneAndUpdate or other query, and it works fine, is the problem only happen in aggregate?
– Muhammad Fasalir Rahman
Mar 24 '16 at 4:59
1
1
@MuhammadFasalirRahman This is exactly what I answered with. A
.find()
can use the Schema
which of course has a default type of ObjectId
for the _id
field. Aggregation pipelines do not use the Schema
, as I actually already explained.– Blakes Seven
Mar 24 '16 at 5:06
@MuhammadFasalirRahman This is exactly what I answered with. A
.find()
can use the Schema
which of course has a default type of ObjectId
for the _id
field. Aggregation pipelines do not use the Schema
, as I actually already explained.– Blakes Seven
Mar 24 '16 at 5:06
This is not working in mongoose 5
– Mina Luke
Feb 28 at 1:28
This is not working in mongoose 5
– Mina Luke
Feb 28 at 1:28
took me three days to get here; sigh.. I created a lamda inside my schema static method
const castUserId = (userId) => mongoose.Types.ObjectId(userId)
now i'm happy– timebandit
Jun 19 at 17:23
took me three days to get here; sigh.. I created a lamda inside my schema static method
const castUserId = (userId) => mongoose.Types.ObjectId(userId)
now i'm happy– timebandit
Jun 19 at 17:23
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f36193289%2fmoongoose-aggregate-match-does-not-match-ids%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown