I've a problem with a Mongoose backend. i guess its an asynchronous problem. Can someone try to explain me how countDocuments works?
albumFields.features = [];
for await (const feature of features) {
await Artist.countDocuments({ _id: feature._id }, (err, count) => {
if (count > 0) {
albumFields.features.push({ _id: feature._id });
}
console.log('artist.count', albumFields.features);
});
console.log('features.forEach', albumFields.features);
}
console.log('!!!', albumFields.features);
the output im getting is:
artist.count [ { _id: '5ec09f9c99339f3ad85973c0' } ]
features.forEach [ { _id: '5ec09f9c99339f3ad85973c0' } ]
features.forEach [ { _id: '5ec09f9c99339f3ad85973c0' } ]
!!! [ { _id: '5ec09f9c99339f3ad85973c0' } ]
artist.count [ { _id: '5ec09f9c99339f3ad85973c0' },
{ _id: '5ec09fb199339f3ad85973c4' } ]
The output i would expect is:
artist.count [ { _id: '5ec09f9c99339f3ad85973c0' } ]
features.forEach [ { _id: '5ec09f9c99339f3ad85973c0' } ]
artist.count [ { _id: '5ec09f9c99339f3ad85973c0' },
{ _id: '5ec09fb199339f3ad85973c4' } ]
features.forEach [ { _id: '5ec09f9c99339f3ad85973c0' },
{ _id: '5ec09fb199339f3ad85973c4' } ]
!!! [ { _id: '5ec09f9c99339f3ad85973c0' },
{ _id: '5ec09fb199339f3ad85973c4' } ]
So the problem is countDocuments() will return a promise only if there is no call back function. In our case we created the callback which gets the number of documents matching the filter.
I am not sure why the code executed the way it did so maybe someone can explain but I did manage to solve the problem.
let arraytest = [];
for (const feature of features) {
await Artist.countDocuments({ _id: feature._id }).then((count) => {
if (count > 0) {
albumFields.features = [
...albumFields.features,
{ _id: feature._id },
];
}
});
}
For anyone else who runs into the same problem, there was a link on the mongoose documentation which is easy to miss.
https://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#countDocuments
Related
I am using the mongo change stream to update some of my data in the cache. This is the Documentation i am following.
I want to know when one of the keys in my object gets updated.
Schema :- attributes: { position: { type: Number } },
How will I come to know when the position will get updated?
This is how my updateDescription object looks like after updation
updateDescription = {
updatedFields: { 'attributes.position': 1, randomKey: '1234'},
removedFields: []
}
Tried this and its not working
Collection.watch(
[
{
$match: {
$and: [
{ operationType: { $in: ['update'] } },
{
$or: [
{ 'updateDescription.updatedFields[attributes.position]': { $exists: true } },
],
},
],
},
},
],
{ fullDocument: 'updateLookup' },
);
I was able to fix it like this,
const streamUpdates = <CollectionName>.watch(
[
{
$project:
{
'updateDescription.updatedFields': { $objectToArray: '$updateDescription.updatedFields' },
fullDocument: 1,
operationType: 1,
},
},
{
$match: {
$and: [
{ operationType: 'update' },
{
'updateDescription.updatedFields.k': {
$in: [
'attributes.position',
],
},
},
],
},
},
],
{ fullDocument: 'updateLookup' },
);
and then do something with the stream
streamUpdates.on('change', async (next) => {
//your logic
});
Read more here MongoDB
It's my line of code you see below is not working! It always returns an empty array value.
Please help me!
That's working!
const data = await NumbersModel.aggregate([
{
$project: {
Datas: {
$filter: {
input: "$Datas",
as: "data",
cond: { $gte: [ "$$data.time", lastdata ] }
}
}
}
])
That's not working!
const data = await NumbersModel.aggregate([
{
$project: {
Datas: {
$filter: {
input: "$Datas",
as: "data",
cond: {
$and: [
{ $gte: [ "$$data.time", lastdata ], },
{ $eq: [ "$$data.number", req.query.number ] }
]
}
}
}
}
}
])
It's working :)
const data = await NumbersModel.find({ "Datas.time": { $gte: lastdata }, Number: req.query.number })
I need the expert advice for this code. I need to know Is there any better way to solve this.
I am using the mongoose for db. I have a dataset like this:
Below is matchTable:
{
_id: 617bc0113176d717f4ddd6ce,
car: [],
status: true
},
{
_id: 617bc0113176d717f4ddd6cg,
car: [
{
aid: '5c1b4ffd18e2d84b7d6febcg',
}
],
status: true
}
And I have a Car table in which car name is there on behalf of id
like this
{ _id: ObjectId('5c1b4ffd18e2d84b7d6febce'), name: 'ford' },
{ _id: ObjectId('5c1b4ffd18e2d84b7d6febcg'), name: 'mitsubishi' },
So I want to make join the data from car table, so that response get name on behalf of aid.
Desired result will be like
{
_id: 617bc0113176d717f4ddd6ce,
car: [],
status: true
},
{
_id: 617bc0113176d717f4ddd6cg,
car: [
{
aid: '5c1b4ffd18e2d84b7d6febcg',
name: 'mitsubishi'
}
],
status: true
}
For that I have to merge the car table on matchTable. I have done this but I want to give some suggestion that is there any better way to do or is it fine. I need expert advice.
const getData = await matchTable.find(
{ status: true }
).lean().exec();
let dataHolder = [];
await Promise.all (
getData.map(async x => {
await Promise.all(
x.car.map(async y => {
let data = await Car.findOne(
{ _id: ObjectId(y.aid) },
{ name: 1 }
).lean().exec();
y.name = '';
if (data) {
y.name = data.name;
}
})
)
// If I return { ...x }, then on response it will return {}, {} on car column
dataHolder.push(x) //So I have chosen this approach
})
);
Please guide me if any better and efficient solution is there. Thanks in advance
You can make use of aggregation here.
const pipeline = [
{
$match : { status : true }
},
{
$unwind: '$matchtable',
},
{
$lookup: {
from: "cars",
localField: "car.aid",
foreignField: "_id",
as: "matchcars"
}
},
{
$addFields: {
"car.carName": { $arrayElemAt: ["$matchcars.name", 0] }
}
},
{
$group: {
_id: "$_id",
cars: { $push: "$matchcars" }
}
}
]
const result = await matchTable.aggregate(pipeline).exec();
Please make sure, aid field inside car array (in matchTable collection) is an ObjectId because its being matched to _id (which is an ObjectId) inside cars collection.
how to delete the "extras" with "id_extra = 8523" of the "book" "id_book = 8522" of that particular user?, I currently use mongoosejs but I didn't succeed, I tried many stuffs, but whatever I tried was working just till the first level of nested doc.
{
"_id":{
"$oid":"5e32fce08919b53ad66cf694"
},
"user_id":{
"$numberInt":"258787"
},
"username":"daaaa",
"firstname":"davide",
"api_key":"7b031c21edf1237c554867622ad1154f",
"books":[
{
"_id":{
"$oid":"5e356323a0ef6319ebb60162"
},
"id_book":{
"$numberInt":"8522"
},
"blob_annotation":null,
"extra_id":{
"$numberInt":"995176"
},
"extras":[
{
"_id":{
"$oid":"5e356324a0ef6319ebb60163"
},
"id_extra":{
"$numberInt":"8523"
},
"type":"gallery_audio",
"label":"Inverno a Boscodirovo"
},
{
"_id":{
"$oid":"5e356324a0ef6319ebb60164"
},
"id_extra":{
"$numberInt":"8524"
},
"type":"gallery_audio",
"label":"Storia di Primavera"
}
],
"raccolte":[
]
}
],
}
Try using elemMatch in conjunction with $:
db.books.update(
{
books: {
$elemMatch: {
"id_book": 8522,
"extras.id_extra": 8523
}
},
user_id: 258787
},
{
$pull: {
"books.$.extras": {
"id_extra": 8523
}
}
}
)
You may do this trick: Filter "extras" with "id_extra = 8523" of the "book" "id_book = 8522" and save documents again in MongoDB
db.collection.aggregate([
{
$match: {
"books.id_book": 8522
}
},
{
$addFields: {
"books": {
$reduce: {
input: "$books",
initialValue: [],
in: {
$concatArrays: [
"$$value",
[
{
_id: "$$this._id",
id_book: "$$this.id_book",
blob_annotation: "$$this.blob_annotation",
extra_id: "$$this.extra_id",
raccolte: "$$this.raccolte",
extras: {
$filter: {
input: "$$this.extras",
cond: {
$ne: [
"$$this.id_extra",
8523
]
}
}
}
}
]
]
}
}
}
}
}
])
MongoPlayground
how to make a mongodb collection find (db.collection.find) with empty values?
currently i have:
function test(s) {
if (!s) {
return null;
} else {
return s;
}
}
var content = {
date: {
from: '2017-10-15',
to: '2017-11-15'
},
'name': 'some text', //this can be null or empty
'text': 'some other text' //this can be null or empty
}
col.find({
"date": {
$gte: new Date(content.date.from),
$lte: new Date(content.date.to)
},
"name": {
$ne: {
$type: null
},
$eq: test(content.name)
},
"text": {
$ne: {
$type: null
},
$eq: test(content.text)
},
}).toArray((err, items) => {
console.log(items)
});
but it returns an empty array, because "name" or "text" is null / an empty string,
i want that it query only the values that have something specified or ignore it (like content.name is something in it or its empty)
how do i get it? i already searched ... but didnt found something
thanks!
( already testet mongoDB : multi value field search ignoring null fields)
Versions:
Node: 8.9.0
(npm) mongodb: 2.2.33
mongodb: 3.4
Try using $and, $or operators. Something like.
col.find({
$and:[
{"date": {$gte: new Date(content.date.from),$lte: new Date(content.date.to)}},
{"$or":[{"name": {$ne: {$type: null}}},{"name":test(content.name)}]},
{"$or":[{"text": {$ne: {$type: null}}},{"text":test(content.text)}]}
]
}).toArray((err, items) => {
console.log(items)
});
col.find({
$and: [
{
$and: [
{
"date": {
$gte: new Date(content.date.from)
}
},
{
"date": {
$lte: new Date(content.date.to)
}
},
]
},
{
$or: [
{ 'name': null },
{ 'name': content.name }
]
},
{
$or: [
{ 'text': null },
{ 'text': content.text }
]
}
]
})
Edited:
col.find({
$and: [
{
$and: [
{
"date": {
$gte: new Date(content.date.from)
}
},
{
"date": {
$lte: new Date(content.date.to)
}
},
]
},
{
$or: [
{ 'name': null },
{ 'name':'' }
{ 'name': content.name }
]
},
{
$or: [
{ 'text': null },
{ 'text': '' },
{ 'text': content.text }
]
}
]
})
null and empty is different, you need to add one more condition for empty string in query.
Logical Query Operators