I have the following document structure.
{
"_id" : "0026",
"description" : "test",
"name" : "test",
"options" : [
{
"_id" : "002",
"color" : true,
"visible" : true,
"label" : "sample",
},
{
"_id" : "003",
"color" : true,
"visible" : true,
"label" : "sample",
}
],
},
{
"_id" : "0027",
"description" : "test",
"name" : "test",
"options" : [
{
"_id" : "001",
"color" : true,
"visible" : true,
"label" : "sample",
},
{
"_id" : "002",
"color" : true,
"visible" : true,
"label" : "sample",
}
],
},
I am trying to return one array of only the 'options' subdocuments that match an options label regex search.
I think I'm pretty much there but I seem to getting back a separate array of options for each document, how do I return just one array of 'options'?
My current code is:
{
$match: {
options: {
$elemMatch: {
label: { $regex: '^sample', $options: 'i' },
},
},
},
},
{ "$unwind": '$options' },
{
$project: {
_id: 0,
options: 1,
},
},
The structure I would like back is just an array of options:
[
{
"_id" : "001",
"color" : true,
"visible" : true,
"label" : "sample",
},
{
"_id" : "002",
"color" : true,
"visible" : true,
"label" : "sample",
},
{
"_id" : "002",
"color" : true,
"visible" : true,
"label" : "sample",
},
{
"_id" : "003",
"color" : true,
"visible" : true,
"label" : "sample",
}
]
Ta.
Always the way, you post a question then finally get the answer yourself!
Just needed to add:
{ $replaceRoot: { newRoot: '$options' } }
as the last step.
Full answer:
{
$match: {
options: {
$elemMatch: {
label: { $regex: '^sample', $options: 'i' },
},
},
},
},
{ "$unwind": '$options' },
{
$project: {
_id: 0,
options: 1,
},
},
{ $replaceRoot: { newRoot: '$options' } },
Related
I need to group following documents by featured and trending.
[
{
"_id" : ObjectId("5f22546cd49ffe0d6f087a2e"),
"title" : "....",
"image" : "...",
"featured" : true,
"trending" : false,
"creationDate" : ISODate("2020-07-30T05:02:36.592Z")
},
{
"_id" : ObjectId("5f22546cd49ffe0d6f087a2f"),
"title" : "Cras non dolor",
"image" : "...",
"featured" : false,
"trending" : true,
"creationDate" : ISODate("2020-07-30T05:02:36.592Z")
}
]
So, after grouping they should be in following format -
[
{
_id: null,
featured: [
{
"_id" : ObjectId("5f22546cd49ffe0d6f087a2e"),
"title" : "....",
"image" : "...",
"featured" : true,
"trending" : false,
"creationDate" : ISODate("2020-07-30T05:02:36.592Z")
}
],
trending: [
{
"_id" : ObjectId("5f22546cd49ffe0d6f087a2f"),
"title" : "Cras non dolor",
"image" : "...",
"featured" : false,
"trending" : true,
"creationDate" : ISODate("2020-07-30T05:02:36.592Z")
}
]
}
]
How can I get this result through aggregation or any other way?
I have been trying with aggregate $group. But I can't figure out how can I $group via featured/trending value with equal true.
So, I don't need corresponding false value when grouping them. Also, there might have other fields like highlighted etc along with featured trending.
This is quite easy to achieve, the easiest way to do it is using $facet
db.collection.aggregate([
{
$facet: {
featured: [
{
$match: {
"featured": true
}
}
],
trending: [
{
$match: {
"trending": true
}
}
]
}
}
])
MongoPlayground
How its making listing order by records array's value with subquery
I want best query for perform in mongo side
models.js
new ms.Schema({
name : {type: String,required: true,unique:true},
display_name: {type: String,required: true,unique:true},
url: {type: String,default:'' },
icon: {type: String,default :'no.png' },
assets : {type:Array,default : ['BTCUSDT']},
active: {type: Boolean, default : true},
})
mongodb's record goes here
{
"_id" : ObjectId("5e9e78c477b1c7a1bfc4978c"),
"url" : "https://bitso.com/",
"active" : false,
"name" : "bitso",
"display_name" : "Bitso",
"icon" : "Bitso.png",
"__v" : 0,
"seq" : 888,
"assets" : [
"BTCUSDT",
"ETHUSDT",
"LTCUSDT"
]
},
{
"_id" : ObjectId("5e9e78c377b1c7a1bfc4978a"),
"url" : "https://www.fybsg.com/",
"active" : false,
"name" : "fybsg",
"display_name" : "FYB-SG",
"icon" : "FYB-SG.png",
"__v" : 0,
"seq" : 888,
"assets" : [
"BTCUSDT",
"ETHUSDT"
]
},
{
"_id" : ObjectId("5e9e78c377b1c7a1bfc49789"),
"url" : "https://hitbtc.com/",
"active" : true,
"name" : "hitbtc",
"display_name" : "Hitbtc",
"icon" : "Hitbtc.png",
"__v" : 0,
"seq" : 99,
"assets" : [
"BCCUSDT"
]
},
{
"_id" : ObjectId("5e9e78c077b1c7a1bfc49787"),
"url" : "https://blockchain.io/",
"active" : false,
"name" : "blockchainio",
"display_name" : "Blockchain.io",
"icon" : "Blockchain.io.png",
"__v" : 0,
"seq" : 999,
"assets" : [
"BTCUSDT",
"ETHUSDT"
]
},
db.markets.aggregate([...])
if possible How can i export result like here from mongo records; Else what algorithm must i use
i need data like this
[
BTCUSDT : { which record assets have BTCUSDT listings },
ETHUSDT : { which record assets have BTCUSDT listings},
...
]
You need to flat assets array of each doc using $unwind stage and after that just group them by this field:
db.markets.aggregate([
{
$unwind: "$assets"
},
{
$group: {
_id: "$assets",
recordId: {
$push: "$_id"
}
}
}
])
You output will be:
[
{
"_id": "BCCUSDT",
"recordId": [
"5e9e78c377b1c7a1bfc49789"
]
},
{
"_id": "BTCUSDT",
"recordId": [
"5e9e78c477b1c7a1bfc4978c",
"5e9e78c377b1c7a1bfc4978a",
"5e9e78c077b1c7a1bfc49787"
]
},
{
"_id": "LTCUSDT",
"recordId": [
"5e9e78c477b1c7a1bfc4978c"
]
},
{
"_id": "ETHUSDT",
"recordId": [
"5e9e78c477b1c7a1bfc4978c",
"5e9e78c377b1c7a1bfc4978a",
"5e9e78c077b1c7a1bfc49787"
]
}
]
If it's more convinient for you to get only one object as the result, you can additionally group them by null id, store all the docs in array with k, v properties and replace the root of the single document:
{
$group: {
_id: null,
result: {
$push: {
k: "$_id",
v: "$recordId"
}
}
}
},
{
$addFields: {
result: {
$arrayToObject: "$result"
}
}
},
{
$replaceRoot: {
newRoot: "$result"
}
}
Result for whole query will be:
[
{
"BCCUSDT": [
"5e9e78c377b1c7a1bfc49789"
],
"BTCUSDT": [
"5e9e78c477b1c7a1bfc4978c",
"5e9e78c377b1c7a1bfc4978a",
"5e9e78c077b1c7a1bfc49787"
],
"ETHUSDT": [
"5e9e78c477b1c7a1bfc4978c",
"5e9e78c377b1c7a1bfc4978a",
"5e9e78c077b1c7a1bfc49787"
],
"LTCUSDT": [
"5e9e78c477b1c7a1bfc4978c"
]
}
]
Say if I have a result like this:
{
"_id" : ObjectId("5b722d06c23b5f2bd0329a41"),
"name" : "test",
"item" : {
"_id" : ObjectId("5b722d07c23b5f2bd0329a53"),
"display_name" : "",
"image" : "http://via.placeholder.com/700x500/ffffff/000000/?text=No%20Image&",
"is_private" : true,
"details" : [
{
"is_private" : false,
"type" : "text",
"_id" : ObjectId("5b722d06c23b5f2bd0329a44"),
"title" : "Name",
"content" : "",
"order" : 0
},
{
"is_private" : false,
"type" : "text",
"_id" : ObjectId("5b722d06c23b5f2bd0329a43"),
"title" : "Price",
"content" : "",
"order" : 1
},
{
"is_private" : false,
"type" : "text",
"_id" : ObjectId("5b722d06c23b5f2bd0329a42"),
"title" : "Company",
"content" : "",
"order" : 2
}
],
"tags" : [ ],
"__v" : 0
}
}
and I want to filter by item.details.is_private, how should I do this? I want to return all properties of item but filter out any item.details.is_private if it is true
I am currently projecting it as:
{
"$project": {
name: 1,
item: 1
}
}
but am not sure how to implement $filter in this setting
You can try using $addsFields with $filter aggregation
db.collection.aggregate([
{ "$addFields": {
"item.details": {
"$filter": {
"input": "$item.details",
"as": "detail",
"cond": {
"$eq": [ "$$detail.is_private", true ]
}
}
}
}}
])
This is the current object
{
"chargeCodeIds" : [
1,
2
],
"customChargeCode" : [
{
"_id" : 1,
"chargeCodeType" : "Department",
"name" : "IT",
"isBillable" : true,
},
{
"_id" : 2,
"chargeCodeType" : "Task"
"name" : "Development",
"isBillable" : true
}
]
We have the query that searched the charge codes from their collection say "customChargeCode" and listed them in an object "customChargeCode" as array of objects. BUT I don't want it an in array.
Here is the current query:
db.authorizeChargeAssociation.aggregate([
{
$project: {
chargeCodeIds: {
$map: {
input: {
$map: {
input:"$chargeCodes",
in: {
$arrayElemAt: [{$objectToArray: "$$this"}, 1]
},
}
},
in: "$$this.v"
}
},
}
},
{
$lookup: {
from: "customChargeCode",
localField:"chargeCodeIds",
foreignField:"_id",
as:"customChargeCode"
}
},
{$unwind: {path: "$customChargeCodes", preserveNullAndEmptyArrays: true} },
],
{ collation: { locale: "en_US", numericOrdering: true}},
{ allowDiskUse: true}
)
What I want is to get a separate object of each "chargeCodeIds" from the "customChargeCode" collection and name them the field as "chargeCodeType" value.
Expected Result be like:
{
"chargeCodeIds" : [
1,
2
],
"Department" : {
"_id" : 1,
"chargeCodeType" : "Department",
"name" : "IT",
"isBillable" : true,
},
"Task" : {
"_id" : 2,
"chargeCodeType" : "Task"
"name" : "Development",
"isBillable" : true
}
Whether a user sends or receives a message, he/she should be able to archive the message for him/herself.
This .aggregate $or, however, only returns docs that the user is the recipient of ('to') that he/she has marked 'archive':'true'. It does accurately filter messages according to the 'value' Booleans.
Models.Messages.aggregate([
// Match documents
{ "$match": {
"$or" : [
{
"to": {
"$elemMatch": {
"username": 'userA',
"view.archive": true,
"view.bin": false
}
}
},
{
"from" : {
"$elemMatch" : {
"username" : 'userA',
"view.archive": true,
"view.bin": false
}
}
}
],
"$or": [
{ 'value.1': true },
{ 'value.2': true },
{ 'value.3': true },
{ 'value.4': false }
]
}},
// Unwind to de-normalize
{ "$unwind": "$to" },
{ "$unwind": "$from" },
// Match the array elements
{ "$match": {
"to.username": 'userA',
"to.view.archive": true,
"from.username": 'userA',
"from.view.archive": true
}},
// Group back all the elements of the original document
{ "$group": {
"_id": "$_id",
"from": { "$push": "$from" },
"to": { "$push": "$to" },
"message": { "$first": "$message" },
"updated": { "$first": "$updated" }
}},
// Sort by updated, most recent first (descending)
{"$sort": {"updated": -1}}
], function (err, docs) {
How could this be altered so that all the fields of both of the following messages are aggregated for userA:
{
"_id" : ObjectId("53e83867f316ea7f22fd3b2b"),
"updated" : ISODate("2014-08-11T03:29:06.000Z"),
"message" : "message1",
"value" : [
"1" : true,
"2" : false,
"3" : false,
"4" : false
]
"to" : [
{
"user" : ObjectId("53e835bd76e0d04318d8cc4e"),
"username" : "userA",
"_id" : ObjectId("53e83867f316ea7f22fd3b2c"),
"view" : {
"inbox" : false,
"outbox" : false,
"archive" : true,
"bin" : false
}
}
],
"from" : [
{
"user" : ObjectId("53e8360276e0d04318d8cc55"),
"username" : "userB",
"_id" : ObjectId("53e83867f316ea7f22fd3b2d"),
"view" : {
"inbox" : false,
"outbox" : true,
"archive" : false,
"bin" : false
}
}
],
"__v" : 5
}
{
"_id" : ObjectId("53e83867f316ea7f22fd3b2b"),
"updated" : ISODate("2014-08-11T03:29:06.000Z"),
"message" : "message2",
"value" : [
"1" : false,
"2" : true,
"3" : false,
"4" : false
]
"to" : [
{
"user" : ObjectId("53e8360276e0d04318d8cc55"),
"username" : "userB",
"_id" : ObjectId("53e83867f316ea7f22fd3b2c"),
"view" : {
"inbox" : true,
"outbox" : false,
"archive" : false,
"bin" : false
}
}
],
"from" : [
{
"user" : ObjectId("53e835bd76e0d04318d8cc4e"),
"username" : "userA",
"_id" : ObjectId("53e83867f316ea7f22fd3b2d"),
"view" : {
"inbox" : false,
"outbox" : true,
"archive" : true,
"bin" : false
}
}
],
"__v" : 5
}
You can't have two $or fields at the top level of your first $match object, so you need to wrap those in an $and array like the following if they both need to be satisfied:
{ "$match": {
$and: [{
"$or" : [
{
"to": {
"$elemMatch": {
"username": 'userA',
"view.archive": true,
"view.bin": false
}
}
},
{
"from" : {
"$elemMatch" : {
"username" : 'userA',
"view.archive": true,
"view.bin": false
}
}
}
]}, {
"$or": [
{ 'value.1': true },
{ 'value.2': true },
{ 'value.3': true },
{ 'value.4': false }
]
}
]
}}
There's a lot going on in your pipeline, so this may not be the only problem.