Nodejs/Mongoose fail to compare documents - arrays

I want to take each element of an array of documents I queried and check if it is in an other array of documents I queried
I have this model :
var dataTypeSchema = new Schema({
name : String,
description : String,
// Personnel || Professionel || Intime
category : String,
provenance : {
type : Schema.ObjectId,
ref : 'Service'
}
});
and this one :
var dataUseSchema = new Schema({
purpose : {
type : Schema.ObjectId,
ref : 'Purposes'
},
dataTypes : [{
type : Schema.ObjectId,
ref : 'DataType'
}],
description : String,
service : {
type : Schema.ObjectId,
ref : 'Service'
},
user : {
type : Schema.ObjectId,
ref : 'User'
}
});
I basically query an array of dataTypes and then want to check for each one if it is in a specific dataUse.data
I tried several methods of comparison : includes, indexOf, even comparing each elements _ids, it always returns false
I have checked that both arrays indeed contain documents and that they have some documents in common
Here is my code (one attempt) for comparing, I am first getting an array of DataUses and then for each one I want to check which values it shares with the dataTypesArray
const dataTypesArray = await Service.getServiceDataTypes(req.params.serviceName)
DataUse.find({service : serviceID, user : serviceID})
.populate('purpose dataTypes service user')
.exec()
.then(dataUses => {
for(let j = 0; j < dataUses.length; j++) {
for(let k = 0; k < dataTypesIDs.length; k++) {
if(dataUses[j].dataTypes.indexOf(dataTypesIDs[k])==-1) {
dataUses[j]["otherData"].push(dataTypesIDs[k])
}
}
}
return dataUseArray
})
.catch(console.log)
For the last if (condition), everything sets equal to -1
Both dataTypes arrays are populated, but as I said I tried comparing just _id and still same result
thanks !

Here is how you can do it...
To compare an array with other of Mongoose Array.
See the IDs your are getting are mongoose ObjectID which is an object
To compare an Array of ObjectID with other ObjectID:
// converting dataTypes to String,
// you can also convert it by using `lean`
// i.e Model.find().lean().exec()
// this would return JavascriptObject instead of MongooseModel
dataTypeIDs = dataTypes.map(i => i.toString()); // converting to plain
// Array of string
dataTypeIDs.indexOf(someDataTypeID.toString()); // returns -1 if not found
You can use the last line to convert it anyway you like in your if (condition)
Change this block of code like this:
.then(dataUses => {
// assuming its an Array of ObjectID
dataTypesIDsArray = dataTypesIDs.map(i => i.toString())
for(let j = 0; j < dataUses.length; j++) {
usesDataTypes = dataUses[j].dataTypes.map(i => i.toString())
for(let k = 0; k < dataTypesIDsArray.length; k++) {
if(usesDataTypes.indexOf(dataTypesIDsArray[k]) == -1) {
dataUses[j]["otherData"].push(dataTypesIDsArray[k])
// use ObjectID from mongoDB if you want to cast it to "ObjectId"
}
}
}
return dataUseArray;
})
Its not tested, but I have taken reference of an existing tested code from my project.

Related

Skipping loop iterations based on type?

I have an array of both objects (JSX elements) and strings, which I want to iterate over and perform logic on the items that are strings, but skip the objects.
const array= ['string', {...}, {...}, 'string', 'string', {...}];
for (let i = 0; i < array.length ; i++) { if( {/* This is an object */} ){continue;}else{
{/* perform logic */}}
Is is possible to continue a loop based on type?
The typeof operator should do what you want. However, if the logic you wish to perform only works on strings then you may want to consider inverting your logic to guard against the potential for your array to contain additional data types in the future.
Something like:
const array= ['string', {...}, {...}, 'string', 'string', {...}];
for (let i = 0; i < array.length ; i++) {
const str = array[i]
if( typeof str === 'string'){
/* perform logic on str */
}
See the typeof operator.
eg.
if (typeof array[i] !== 'string') {
continue;
}

using array for URLSearchParams in vue3

i want to append key and value of array , using for axos request
here is the array
const
schedule = ref({
"userId" : 13,
"sunday" : ["mornig","afternoon","nigh"],
"monday" : ["afternoon","nigh"],
"wednesday" : ["mornig","afternoon"]
})
to append manuallya i can do like this
params.append("userId",data.value.userId)
params.append("sunday[0]",data.value.sunday[0])
params.append("sunday[1]",data.value.sunday[1])
params.append("sunday[2]",data.value.sunday[2])
params.append("monday[0]",data.value.monday[0])
params.append("monday[1]",data.value.monday[1])
params.append("wednesday[0]",data.value.wednesday[0])
params.append("wednesday[1]",data.value.wednesday[1])
but this will be problim if length of the schedule time l (morning,night ...) unknown
i do like this
let i = 0
for(let j in data.value){
console.log(j+$[i++])
}
and also loop using for in and for of , but none of them are success
You "just" need to do a nested iteration. Loop through object, and if any value is an array, loop through the array. Here's an example code to flatten the dataset. Just note that instead of flattenData(schedule) you'd need to pass the ref's value with flattenData(schedule.value).
const schedule = {
userId: 13,
sunday: ["mornig", "afternoon", "nigh"],
monday: ["afternoon", "nigh"],
wednesday: ["morning", "afternoon"],
};
function flattenData(data) {
const o = {};
Object.keys(data).forEach((dataKey) => {
if (Array.isArray(data[dataKey])) {
data[dataKey].forEach(
(_, nestedArrayIndex) =>
(o[`${dataKey}[${nestedArrayIndex}]`] =
data[dataKey][nestedArrayIndex])
);
} else {
o[dataKey] = data[dataKey];
}
});
return o;
}
// show flattened data
console.log(flattenData(schedule));
// prepare params
const params = new URLSearchParams("");
// populate
Object.entries(flattenData(schedule)).forEach(([k,v]) => params.append(k, v))
// result:
console.log(params.toString())

Modify an array element after finding it in swift does not work

I wrote a model like this as an exercise :
struct Store {
var name : String
var bills : Array<Bill>
var category : Category?
}
struct Bill {
var date : String
var amount : Float
}
struct Category {
var name : String
var tags : Array<String>
}
and when I'm searching if a store already exist to add a bill to it instead of creating a new store, my code doesn't work. It acts like if the result of the search is a copy of the Array element . I would like to have a reference.
var stores : Array <Store> = Array()
for billStatment in billStatements! {
let billParts = billStatment.split(separator: ",")
if billParts.count > 0 {
let bill : Bill = Bill(date:String(billParts[0]), amount: Float(billParts[2])!)
var store : Store = Store(name:String(billParts[1]), bills: [bill], category: nil)
if var alreadyAddedStore = stores.first(where: {$0.name == String(billParts[1])}) {
alreadyAddedStore.bills.append(bill)
print("yeah found it \(alreadyAddedStore)") // the debugger breaks here so I know the "first" method is working. If I print alreadyAddedStore here I have one more element, that's fine.
} else {
stores.append(store)
}
}
}
print("\(stores.count)") // If I break here for a given store that should contains multiple elements, I will see only the first one added in the else statement.
Can anyone tell me what I am doing wrong?
As already noted, you're confusing value (struct) semantics with reference (class) semantics.
One simple fix would be the change stores to a dictionary with the name as your key:
var stores : Dictionary<String, Store> = [:]
and use it like this:
if(stores[store.name] == nil) {
stores[store.name] = store
}
else {
stores[storeName].bills.append(bill)
}

What is the Best way to loop over an array in scala

I'm new to scala and I'm trying to refactor the below code.I want to eliminate "index" used in the below code and loop over the array to fetch data.
subgroupMetricIndividual.instances.foreach { instanceIndividual =>
val MetricContextListBuffer: ListBuffer[Context] = ListBuffer()
var index = 0
contextListBufferForSubGroup.foreach { contextIndividual =>
MetricContextListBuffer += Context(
entity = contextIndividual,
value = instanceIndividual(index).toString
)
index += 1
}
}
For instance, if the values of variables are as below:
contextListBufferForSubGroup = ("context1","context2")
subgroupMetricIndividual.instances = {{"Inst1","Inst2",1},{"Inst3","Inst4",2}}
Then Context should be something like:
{
entity: "context1",
value: "Inst1"
},
{
entity: "context2",
value: "Inst2"
},
{
entity: "context1",
value: "Inst3"
},
{
entity: "context2",
value: "Inst4"
}
Note:
instanceIndividual can have more elements than those in contextListBufferForSubGroup. We must ignore the last extra elements in instanceIndividual in this case
You can zip two lists into a list of tuples and then map over that.
e.g.
subgroupMetricIndividual.instances.foreach { instanceIndividual =>
val MetricContextListBuffer = contextListBufferForSubGroup.zip(instanceIndividual).map {
case (contextIndividual, instanceIndividualIndex) => Context(
entity = contextIndividual,
value = instanceIndividualIndex.toString
)
}
}
If Context can be called like a function i.e. Context(contextIndividual, instanceIndividualIndex.toString) then you can write this even shorter.
subgroupMetricIndividual.instances.foreach { instanceIndividual =>
val MetricContextListBuffer = contextListBufferForSubGroup
.zip(instanceIndividual.map(_.toString)).map(Context.tupled)
}
Without knowing your exact datatypes, I'm mocked up something which is probably close to what you want, and is slightly more functional using maps, and immutable collections
case class Context(entity:String, value:String)
val contextListBufferForSubGroup = List("context1","context2")
val subgroupMetricIndividualInstances = List(List("Inst1","Inst2",1),List("Inst3","Inst4",2))
val result: List[Context] = subgroupMetricIndividualInstances.map { instanceIndividual =>
contextListBufferForSubGroup.zip(instanceIndividual) map { case v: (String, String) =>
Context(
entity = v._1,
value = v._2
)
}
}.flatten

Select the first JSON array child value

I want to get the value that holds the first child of a JSON array.
This is the array :
var sms = {
'1' : {
'address' : '+123',
'body' : 'SMS1'
},
'2' : {
'address' : '+123',
'body' : 'SMS2'
},
'3' : {
'address' : '+123',
'body' : 'SMS3'
},
'4' : {
'address' : '+123',
'body' : 'SMS4'
}
};
The reason is i want to loop in it to search a string using the first childs
value as it is above. Example sms.[0] = 1;
You can loop over the object using a using the in notation. Use hasOwnProperty to avoid getting references in the object
for (ii in sms) {
if (sms.hasOwnProperty(ii)) {
console.log(ii, sms[ii], sms[ii]['address'], sms[ii]['body']);
}
}
If you want to access the first child's value you can use
sms['1']
Which will return an object. If you want to access the values to the keys inside that object, you can use sms['1']['address'] or sms['1']['body'].
The first [] accesses the child of the first layer of JSON, and the second [<key_name>] accesses the value of the second layer of JSON, containing keys and values.
I don't know if I follow your instructions, but try this to access each element of this JSON.
for(i in sms){
console.log(sms[i]);
}
You can JSON api to parse the JSON input and fetch the respective child
JSONObject obj = new JSONObject(stringData);
JSONArray resultArr = obj.getJSONArray("sms");
JSONArray headrArr = null;
JSONObject jo = resultArr.optJSONObject(0);
if(jo != null){
headrArr = jo.names();
}
System.out.println(headrArr.get(0));

Resources