I have a cluster on atlas. My current object seems like below:
{
"_id": {
"$oid":"5e9d8ccfb3d80e3824bf856c"
},
"user": {
"name":"test",
"channelGroups": [
{
"active": true,
"name": "an example of test",
"creationDate": "20 Apr 2020 at 13:35 PM",
"summary": "an example summary",
"channels": []
}
]
},
"__v": {
"$numberInt":"0"
}
}
Here is my controller method: ( I use mongoose with express )
createANewChannel: (req, res) => {
channelGroupModel.findOneAndUpdate({
"user.name": "test", "user.channelGroups": {
$elemMatch: {
"name": "an example of test" // req.params.slug
}
}
}, { $push: {
"channelGroups.channels": {
filter: {
keyword: "#example",
keywordType: "hashtag",
active: true,
fetchFrequency: 1,
},
tweets: []
}
}
},
(error, success) => {
if (error) {
console.log(error);
} else {
console.log(success);
}
}
);
res.send('ok');
},
Problem:
I want to push a new channel object into the channelGroups array according to channelGroups' name value. My code works but nothing happens.
=====================================================================
Updated working version:
channelGroupModel.findOneAndUpdate(
{
"user.name": "test"
},
{
$push: {
"user.channelGroups.$[elem].channels": {
filter: {
keyword: "#example",
keywordType: "hashtag",
active: true,
fetchFrequency: 1,
},
tweets: []
}
}
},
{
arrayFilters: [{"elem.name": "an example of test"}]
},
(error, success) => {
if (error) {
console.log(error);
} else {
console.log(success);
}
}
)
You want to use arrayFilters:
channelGroupModel.findOneAndUpdate(
{
"user.name": "test"
},
{
$push: {
"channelGroups.$[elem].channels": {
filter: {
keyword: "#example",
keywordType: "hashtag",
active: true,
fetchFrequency: 1,
},
tweets: []
}
}
},
{
arrayFilters: [{"elem.name": "an example of test"}]
},
(error, success) => {
if (error) {
console.log(error);
} else {
console.log(success);
}
}
)
Just FYI mongoose has a notorious bug on certain versions when it comes to arrayFilters.
Related
i am receiving a string "city" from "req.body"
my function:
async function searchProject(req: Request, res: Response) {
const { code, archiveNumber, air, city, municipality, origin } = req.body;
console.log(city);
try {
const projects = await Project.find({
$or: [
{ code: { $regex: code ?? "" } },
{ archiveNumber },
{ air },
{
city: {
$in: [city, "$city.value"],
},
},
{ municipality },
{ origin },
],
});
if (!projects)
return res.status(400).json({ message: "Pas de projet trouvée" });
res.status(200).json(projects);
} catch (err) {
console.log(err);
res.status(500).json({ message: "Server Error" });
}
}
i am using $or operator to get projects that matches at least on the values that receive from "req.body", all other values seem to work but "city".
in my document, here is how city looks like:
"city": [
{
"id": "62ed0121f58a5ed78ac05a85",
"value": "City 1"
}
],
now how can i compare a "city" which i get from "req.body" with "city.value" ?
Solved!!!
i tried:
const projects = await Project.find({
$or: [
{ code: { $regex: code ?? "" } },
{ archiveNumber },
{ air },
{ municipality },
{ origin },
],
}).elemMatch("city", {
value: city,
});
and it worked
thanks to
Siddhesh Khadapkar
I want to stream a MongoDB query in NodeJS because, in Angular, i have a chart and i want to update the data without making a refresh.
So far, this is my code (NodeJS):
exports.gettoday = function (request, response) {
db.collection("nifi5", function (err, collection) {
collection
.aggregate([
{
$group: {
_id: {
minute: {
$minute: { $dateFromString: { dateString: "$created_at" } },
},
hour: {
$hour: { $dateFromString: { dateString: "$created_at" } },
},
day: {
$dayOfMonth: { $dateFromString: { dateString: "$created_at" } },
},
month: {
$month: { $dateFromString: { dateString: "$created_at" } },
},
year: {
$year: { $dateFromString: { dateString: "$created_at" } },
},
},
avg: { $avg: "$value_temperature" },
},
},
])
.stream()
.toArray(function (err, items) {
if (err) {
response.statusMessage = {
devMessage: err,
clientMessage: "Unexpected error, try again latter",
};
response.send(response.statusMessage).end();
}
let tarray = { labels: [], data: [] };
items.forEach((element) => {
element.date = element._id.hour + ":" + element._id.minute;
element.avg = Math.round(element.avg * 100) / 100;
});
items.sort(function (a, b) {
return a.date < b.date ? -1 : 1;
});
items.forEach((element) => {
tarray.labels.push(element.date);
tarray.data.push(element.avg);
});
return response.json(tarray);
});
});
};
Angular:
gettodaydata(): Observable<any> {
return this.http.get(`${environment.baseURL}gettoday`).subscribe((data) => {
this.data_line.push(...data.data);
this.labels_line.push(...data.labels);
this.isLineChartLoading = false;
});
}
Can u please help me streaming this controller and fetch the data in Angular to update my chart when new data comes do my database ?
Thank you all!
You should give a try to socket.io, it creates a persistent connection and responds to events in real time.
function getConversations(filter,res){
client.search({
index: "conversations",
type: "docs",
body: {
"query": {
"bool": {
"should": [{
"range": {
"followers_count": {
"gte": filter.followers_count_range.gte,
"lte": filter.followers_count_range.lte
}
}
},
{
"match": {
"user_gender": filter.gender
}
},
{
"match": {
"dialect": filter.dialect
}
},
{
"match": {
"lang": filter.language
}
}
],
"minimum_should_match":1
}
}
}
}, function(err, resp, status) {
if (err) {
console.log(err);
res.status(400).send({
message: "Not Found"
});
} else {
//console.log("--- Response ---");
console.log(resp);
console.log("--- Hits ---");
resp.hits.hits.forEach(function(hit) {
console.log(hit._source);
});
res.status(200).send({
message: "Done"
});
}
});
}
I am new to elastic search and need more understanding and help.
if one field of the match doesn't exist in the send object it gives an error why, how can I fix that
if my filter has only a name property it doesn't work all property must be in the filter obj
another question
if I want to say that if a language is a specific value I choose to neglect to match the dialect
You can check for the existence of a given filter before passing it to the ES request body with a ternary operator. If it's falsy, use the match_all query which is essentially the Elasticsearch equivalent a no-operation:
{
query: {
bool: {
should: [
{
range: {
followers_count: {
gte: filter.followers_count_range.gte,
lte: filter.followers_count_range.lte
}
}
},
filter.gender
? {
match: {
user_gender: filter.gender
}
}
: {
match_all: {}
},
filter.dialect
? {
match: {
dialect: filter.dialect
}
}
: {
match_all: {}
},
filter.language
? {
match: {
lang: filter.language
}
}
: { match_all: {} }
],
minimum_should_match: 1
}
}
};
is it possible to update array of object by id? ex.:
This is my array:
[
{
"_id": "5fdb614d686e671eb834a409",
"order": 1,
"title": "first"
},
{
"_id": "5fdb61c0686e671eb834a41e",
"order": 2,
"title": "second"
},
{
"_id": "5fdb61d6686e671eb834a424",
"order": 3,
"title": "last"
}
]
and I would like to change only the order of each by ID. I am using Node and I tried to do like that:
router.post("/edit-order", auth, async (req, res) => {
try {
const sections = await Section.updateMany(
req.body.map((item) => {
return { _id: item._id }, { $set: { order: item.order } };
})
);
res.json(sections);
} catch (e) {
res.status(500).json({ message: "Something went wrong in /edit-order" });
}
});
my request body is:
[
{
"_id": "5fdb614d686e671eb834a409",
"order": 2
},
{
"_id": "5fdb61c0686e671eb834a41e",
"order": 3
},
{
"_id": "5fdb61d6686e671eb834a424",
"order": 4
}
]
but as a result, I got:
[
{
"_id": "5fdb614d686e671eb834a409",
"order": 4,
"title": "first"
},
{
"_id": "5fdb61c0686e671eb834a41e",
"order": 4,
"title": "second"
},
{
"_id": "5fdb61d6686e671eb834a424",
"order": 4,
"title": "last"
}
]
so, it change every order by the last value of request array. Any ideas how could I manage that. If you know any other solution feel free to share, all what I need is to change order only by id.
Well, since you have a different value of order for each item, you'll need to do a bulkWrite.
router.post('/edit-order', auth, async (req, res) => {
try {
const writeOperations = req.body.map((item) => {
return {
updateOne: {
filter: { _id: item._id },
update: { order: item.order }
}
};
});
await Section.bulkWrite(writeOperations);
res.json(req.body);
} catch (e) {
res.status(500).json({ message: 'Something went wrong in /edit-order' });
}
});
If you had a single value of order to all the items, you could've used updateMany along with $in.
router.post('/edit-order', auth, async (req, res) => {
try {
const sectionsIds = req.body.map((item) => {
return item._id;
});
const sections = await Section.updateMany(
{ _id: { $in: sectionsIds } },
{ order: 'A single value for all sections in body' }
);
res.json(sections);
} catch (e) {
res.status(500).json({ message: 'Something went wrong in /edit-order' });
}
});
I simply want to count the element in array based on the query. I tried the following command but not solved my problem.
I want to count the element whose TimeStamp is in between "2017-02-17T18:30:00.000Z and "2017-02-18T18:29:59.999Z" on DATA2 array, but it returns only 1.
CODE Executed:
CODE 1
db.ABC.aggregate([{
$match: {
$and: [{
DATA2: {
$exists: true
}
}, {
"DATA2.TimeStamp": {
$gte: require('../../modules/getDates').getFromDate(item),
$lte: require('../../modules/getDates').getToDate(item)
}
}, {
Client_id: "123" /*req.query.client_id*/
}]
}
}, {
$project: {
DATASiz: {
$size: "$DATA2"
},
"has bananas": {
$in: ["DATA2.$.TimeStamp"]
}
}
}], function(err, result) {
console.log(result)
callBack();
})
Code 2
db.abc.find({ $and:[{DATA2: {$exists: true}},{Client_id: "123"},{"DATA2": { $elemMatch: { TimeStamp: { $gte: require('../../modules/getDates').getFromDate(item), $lte: require('../../modules/getDates').getToDate(item) } } }}]
}, function(err, result) {
console.log(JSON.stringify(result))
callBack();
})
Code 3
//db.abc.find //also tried
db.abc.count({
$and: [{
DATA2: {
$exists: true
}
}, {
"DATA2.TimeStamp": {
$gte: require('../../modules/getDates').getFromDate(item),
$lte: require('../../modules/getDates').getToDate(item)
}
}, {
Client_id: "123" /*req.query.client_id*/
}]
},{
"DATA2.$":1
}, function(err, result) {
console.log(result)
callBack();
})
JSON Format:
{
"_id": {
"$oid": "57c7404985737e2c78fde6b3"
},
"ABC": "1304258470",
"Status": "Not Found",
"DATA1": [
{123},{123},{123}
],
"Remark": "Not Found",
"DATA2": [
{
"TimeStamp": "2017-02-18T09:01:43.060Z",
"NdrStatus": "Door Locked",
},
{
"TimeStamp": "2017-02-18T08:09:43.347Z",
"NdrStatus": "HOLD",
},
{
"TimeStamp": "2017-02-20T08:09:43.347Z",
"NdrStatus": "HOLD",
}
]
}
Result:
I am getting the first element of DATA2 using CODE 3 but I know that as per the query 2 elements are to return.
I expect 2 as in count.
Also used $unwind $redact
Thanks in advance.
You can use the $filter and $size operators for this:
var start = require('../../modules/getDates').getFromDate(item),
end = require('../../modules/getDates').getToDate(item);
db.ABC.aggregate([
{
"$match": {
"DATA2": { "$exists": true },
"DATA2.TimeStamp": { "$gte": start, "$lte": end },
"Client_id": "123"
}
},
{
"$project": {
"DATASiz": {
"$size": {
"$filter": {
"input": "$DATA2",
"as": "item",
"cond": {
"$and": [
{ "$gte": ["$$item.TimeStamp", start] },
{ "$lte": ["$$item.TimeStamp", end] }
]
}
}
}
}
}
}
], function(err, result) {
console.log(result);
callBack();
});